并未做任何处理,但两次 toString 结果不一致,为啥?

2022-07-13 10:56:56 +08:00
 JinTianYi456
@Configuration
@EnableAsync
@Slf4j
public class ExecutorConfig {
    @Bean("taskExecutor")
    public ThreadPoolTaskExecutor asyncServiceExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        return executor;
    }
}
// test code
        var executor = executorConfig.asyncServiceExecutor();
        System.err.println(System.identityHashCode(executor));
        System.err.println(executor);
        System.err.println(System.identityHashCode(executor));
        System.err.println(executor);
// output
2016053161
org.springframework.cloud.sleuth.instrument.async.LazyTraceThreadPoolTaskExecutor@62730eda
2016053161
org.springframework.cloud.sleuth.instrument.async.LazyTraceThreadPoolTaskExecutor@65d849e0
4722 次点击
所在节点    Java
35 条回复
Aruforce
2022-07-13 17:18:02 +08:00
@JinTianYi456 看了下 sleuth 的源码... sleuth 做了线程池 bean name = taskExecutor 的 wrap 。
看着像是 DefaultAsyncConfigurerSupport 这个类 做的业务逻辑。。
lancelee01
2022-07-13 17:20:24 +08:00
@JinTianYi456 你把你的工程打个包发下吧
yhvictor
2022-07-13 17:39:32 +08:00
查了下 source code: https://github.com/openjdk/jdk/blob/6e18883d8ffd9a7b7d495da05e9859dc1d1a2677/src/java.base/share/classes/java/lang/Object.java#L257

估计是对象是一个对象,但是在两次之间发生了 field 的修改,导致 hashcode 不同
siweipancc
2022-07-14 11:40:29 +08:00
做个实验,Object.class.cast(executor) .toString()
JinTianYi456
2022-07-14 21:17:28 +08:00
@lancelee01 #22 https://t.wss.ink/f/8sqa5iqppnx
JinTianYi456
2022-07-14 21:25:17 +08:00
falsemask
2022-07-14 23:14:58 +08:00
@JinTianYi456 我在 toString()方法打了断点,发现这个线程池是通过代理生成的,最后的 toString()方法也是通过代理执行的,最终调用了 invoke0(method, obj, args),然后一个 native 方法,最后 Object 的 toString(),这里有个 args 对象,每次传的值都不相等,感觉可能是这里的问题(不过也不太确定,毕竟 toString 方法是没有参数的) https://s3.bmp.ovh/imgs/2022/07/14/751ee9ec7e911119.png
redford42
2022-07-14 23:21:45 +08:00
收藏了,debug 出来踢我一下
falsemask
2022-07-14 23:26:01 +08:00
@falsemask 具体也不太确定,对 cglib 不熟,明天上班有空再调一下,或者有人调出来了,踢我一下
zmal
2022-07-15 11:44:41 +08:00
debug 了一下大概明白了。
spring 中注入的 ThreadPoolTaskExecutor 只有一个。但引入了 sleuth 后,它劫持了 executor 的调用。executor 注入 Example.class 后每次调用 executor 内的方法时,都会用这个 executor 包裹一层 LazyTraceThreadPoolTaskExecutor 生成一个新的 LazyTraceThreadPoolTaskExecutor 对象。
zmal
2022-07-15 11:51:23 +08:00
这应该算是早期 LazyTraceThreadPoolTaskExecutor 的一个 bug 。
用最新版的 sleuth 能看到里边多了个 cache ,保存了 ThreadPoolTaskExecutor 和 LazyTraceThreadPoolTaskExecutor 的映射,用来保证同一个 ThreadPoolTaskExecutor 只生成一个 LazyTraceThreadPoolTaskExecutor 。
nothingistrue
2022-07-15 12:28:21 +08:00
既然是已经用了 Spring ,你好像还用了其他的 AOP ,那么 var executor = executorConfig.asyncServiceExecutor(); 弄出来的 executor ,就不一定是前面代码上的 “new ThreadPoolTaskExecutor();”。或者说,executor 对象的类型,不一定是 ThreadPoolTaskExecutor 。这时候用 ThreadPoolTaskExecutor 的 hashCode 和 toString 方法推断的测试结果,可能不是实际结果。
JinTianYi456
2022-07-15 14:01:50 +08:00
@nothingistrue #32 本问题和`那么 var executor = executorConfig.asyncServiceExecutor(); 弄出来的 executor ,就不一定是前面代码上的 “new ThreadPoolTaskExecutor();”`这里,是自己调用`executorConfig.asyncServiceExecutor()`还是 注入 bean `taskExecutor` 是没关系的。test code 里是和这没关系的。
-----------------
另外请看 Configuration#proxyBeanMethods 的说明,它就是同一个 bean (按默认配置的话
JinTianYi456
2022-07-15 14:05:53 +08:00
感谢 zmal , 大家看 #30 #31 即可,谢谢
DonaldY
2022-07-15 23:07:53 +08:00
@JinTianYi456

#30 #31 这个在 sleuth 的 issue 里有对应的提问。

但不能解释为什么 每次执行 System.err.println(executor); executor 都不同。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/865854

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX