并未做任何处理,但两次 toString 结果不一致,为啥? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
JinTianYi456
V2EX    Java

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

  •  
  •   JinTianYi456 2022 年 7 月 13 日 5432 次点击
    这是一个创建于 1382 天前的主题,其中的信息可能已经有所发展或是发生改变。
    @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 
    35 条回复    2022-07-15 23:07:53 +08:00
    lancelee01
        1
    lancelee01  
       2022 年 7 月 13 日
    用 Java 试了一下,是同一个对象。
    ```
    ExecutorService pool = new ThreadPoolExecutor(8, 8, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
    System.out.println(System.identityHashCode(pool));
    System.out.println(pool);
    System.out.println(System.identityHashCode(pool));
    System.out.println(pool);
    ```
    ```

    ```
    lancelee01
        2
    /div> lancelee01  
       2022 年 7 月 13 日
    @lancelee01
    1639705018
    java.util.concurrent.ThreadPoolExecutor@61bbe9ba[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
    1639705018
    java.util.concurrent.ThreadPoolExecutor@61bbe9ba[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
    JinTianYi456
        3
    JinTianYi456  
    OP
       2022 年 7 月 13 日
    @lancelee01 #1 我也觉得是一样的,但你没按照我的环境复现,比如 @Configuration ExecutorConfig ,以及是 LazyTraceThreadPoolTaskExecutor 、、因为我也不知道是哪里影响到了 toString 的结果
    falsemask
        4
    falsemask  
       2022 年 7 月 13 日
    @JinTianYi456 有没有可能和这个异步有关
    JinTianYi456
        5
    JinTianYi456  
    OP
       2022 年 7 月 13 日
    @falsemask #4 只保留 @Configuration 也一样
    wolfie
        6
    wolfie  
       2022 年 7 月 13 日
    你这被 sleuth 增强过吧,看看 LazyTraceThreadPoolTaskExecutor#toString 有没有自定义,或者初始化时候有没有使用匿名内部类覆盖。
    JinTianYi456
        7
    JinTianYi456  
    OP
       2022 年 7 月 13 日
    @wolfie #6 看过了,没有(它这输出样式就基本断定 Object 里的
    Aruforce
        8
    Aruforce  
       2022 年 7 月 13 日
    查下这个类是不是被 spring 加载的。。如果不是。。 @Bean 相关的的 methodInvokeInterceptor 是不生效的
    Aruforce
        9
    Aruforce  
       2022 年 7 月 13 日
    @Aruforce 或者你看下 @Configuration proxyBeanMethods 默认行为是不是 true
    JinTianYi456
        10
    JinTianYi456  
    OP
       2022 年 7 月 13 日
    @Aruforce #9 System.err.println(executor.getClass().getName());
    org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor$$EnhancerBySpringCGLIB$$b9d128b3
    Aruforce
        11
    Aruforce  
       2022 年 7 月 13 日
    @JinTianYi456 System.err.println(executor.getClass().getClassLoader().getClass().getName());
    JinTianYi456
        12
    JinTianYi456  
    OP
       2022 年 7 月 13 日
    @Aruforce #11 java.net.URLClassLoader
    zmal
        13
    zmal  
       2022 年 7 月 13 日
    一模一样的代码试了下:

    1835794313
    org.springframework.cloud.sleuth.instrument.async.LazyTraceThreadPoolTaskExecutor@549ac12c
    1835794313
    org.springframework.cloud.sleuth.instrument.async.LazyTraceThreadPoolTaskExecutor@549ac12c
    BanGanExpert
        14
    BanGanExpert  
       2022 年 7 月 13 日
    把你自己的 test 生成的 class 字节码反编译或者直接贴出来分析,这个明显属于异常行为了呀,现在只有的代码片段理论上看不可能出现这种行为
    BanGanExpert
        15
    BanGanExpert  
       2022 年 7 月 13 日
    如果反编译分析出来没有问题,就必须自己一行行 debug 去看下 JVM 运行时的行为了
    ArthurTsang
        16
    ArthurTsang  
       2022 年 7 月 13 日
    你的确是有 2 个 ThreadPoolTaskExecutor 对象吧? 一个是 @Bean, 一个是手动调用方法 new 出来的
    JinTianYi456
        17
    JinTianYi456  
    OP
       2022 年 7 月 13 日
    @ArthurTsang #16 看 test code ,没有 2 个啊。再说 Configuration#proxyBeanMethods
    lancelee01
        18
    lancelee01  
       2022 年 7 月 13 日
    @ArthurTsang 楼主用的的确没有用 Spring 管理的 bean ,而是通过手动调用 asyncServiceExecutor 方法创建的,但是两次打印的还是同一个对象
    lancelee01
        19
    lancelee01  
       2022 年 7 月 13 日
    @JinTianYi456 改成 Spring-boot 环境两次还是一样,你是不是看错了啊。
    ApplicationContext cOntext= SpringApplication.run(App.class);
    var pool = context.getBean(ExecutorConfig.class).asyncServiceExecutor();
    JinTianYi456
        20
    JinTianYi456  
    OP
       2022 年 7 月 13 日
    @lancelee01 #18 是 spring 管理的,请看 Configuration#proxyBeanMethods 的说明
    2. 即使 `手动调用 asyncServiceExecutor` 我也只调用了一次啊
    Aruforce
        21
    Aruforce  
       2022 年 7 月 13 日
    @JinTianYi456 看了下 sleuth 的源码... sleuth 做了线程池 bean name = taskExecutor 的 wrap 。
    看着像是 DefaultAsyncConfigurerSupport 这个类 做的业务逻辑。。
    lancelee01
        22
    lancelee01  
       2022 年 7 月 13 日
    @JinTianYi456 你把你的工程打个包发下吧
    yhvictor
        23
    yhvictor  
       2022 年 7 月 13 日
    查了下 source code: https://github.com/openjdk/jdk/blob/6e18883d8ffd9a7b7d495da05e9859dc1d1a2677/src/java.base/share/classes/java/lang/Object.java#L257

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

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

    但不能解释为什么 每次执行 System.err.println(executor); executor 都不同。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1995 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 61ms UTC 16:13 PVG 00:13 LAX 09:13 JFK 12:13
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86