问下 Java 大佬,用了 @async 为什么还要使用线程池 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
gosidealone
V2EX    问与答

问下 Java 大佬,用了 @async 为什么还要使用线程池

  •  
  •   gosidealone 2022-05-19 19:56:33 +08:00 2215 次点击
    这是一个创建于 1273 天前的主题,其中的信息可能已经有所发展或是发生改变。
     @Override @Async public void sendTemplateMsg(WxMpTemplateMessage msg,String appid) { TaskExcutor.submit(() -> { String result; try { wxService.switchover(appid); result = wxService.getTemplateMsgService().sendTemplateMsg(msg); } catch (WxErrorException e) { result = e.getMessage(); } //保存发送日志 TemplateMsgLog log = new TemplateMsgLog(msg,appid, result); templateMsgLogService.addLog(log); }); } 

    代码如上,明明是用了 @async 注解,这个注解的本质不是使用了线程池吗?为什么代码里面还要利用线程池去执行?经过尝试,如果去除 TaskExcutor.submit(),这个函数也能异步执行的,那这么写的目的是什么呢? 这是个开源项目,具体可见 https://github.com/niefy/wx-api/blob/master/src/main/java/com/github/niefy/modules/wx/service/impl/TemplateMsgServiceImpl.java

    11 条回复    2022-05-19 23:50:50 +08:00
    dqzcwxb
        1
    dqzcwxb  
       2022-05-19 20:20:47 +08:00
    可能 1,不想占用 @Async 的线程池
    可能 2,wxService.switchover()方法也被 @Async 修饰与 sendTemplateMsg()为父子任务,在 ThreadPoolExecutor 线程池中可能导致死锁
    mmdsun
        2
    mmdsun  
       2022-05-19 20:30:16 +08:00 via iPhone
    不推荐直接用 @Async 注解。虽然现在 spring 提供了这个注解的 yml 配置可以设置大小数量等。但我还是习惯性每个任务分配个线程池的配置,然后再指定名字 @Async("yourName")
    gosidealone
        3
    gosidealone  
    OP
       2022-05-19 20:32:53 +08:00
    @dqzcwxb 1 的情况的话 那这样是不是没使用到 @async 的线程池? 2 的情况我不是很明白,可否详细解释下 谢谢
    gosidealone
        4
    gosidealone  
    OP
       2022-05-19 20:39:24 +08:00
    @mmdsun 是的 一般都是自定义线程池的 但是这里不明白为什么代码里还要手动调用线程池?
    mmdsun
        5
    mmdsun  
       2022-05-19 20:50:16 +08:00 via iPhone
    @gosidealone 这种很常见啊。举个列子:我控制器加方法加 @Async 是为了立即返回数据,为了不阻塞用户操作。但是我里面子有很多任务,10 条*10 需要分批跑数据,这种就需要再开新线程池处理。
        6
    mikicomo  
       2022-05-19 20:51:06 +08:00
    简单看了下,作者应该是希望用 TaskExcutor 中统一管理的线程池去执行系统中的任务,那么从这点看 sendTemplateMsg 上加 @Async 的确有点画蛇添足了,TaskExcutor.submit 直接提交任务即可。

    那么关于这个 @Async 注解为什么这里还加了呢,我个人猜测是,是不是第一版的时候并没有 TaskExcutor ?后来才单独抽出来改造了一版?建议可以看看 git 提交记录,这里我也没 down 代码下来看,不负责任猜测一下
    mikicomo
        7
    mikicomo  
       2022-05-19 21:00:49 +08:00
    另外,sendMsgBatch 方法中循环调用了 this.sendTemplateMsg ,注意同个类下,两个 async 方法相互调用时,@async 会失效,如果作者没有在 sendMsgBatch 另起 TaskExcutor 的话,可能和它的本意不符了( sendMsgBatch 本身虽然是异步,但是内部的循环执行降级为了同步,线程也占用了很久),现在作者的这种写法,是把压力都丢给了 TaskExcutor ,让他慢慢去执行,@async 开出的线程池立马就释放了

    道理是这个道理,但是这么写,其实也不是很建议就是了
    mikicomo
        8
    mikicomo  
       2022-05-19 21:08:51 +08:00
    这里展开说一下,其实自己项目使用自己封装过后的线程池是个好习惯,不过如果只是为了控制线程池个数的话,那倒也大可不必,原生的配置也蛮好。
    一般我们遇到自己封装线程池的场景,主要是为了传递一些系统中的参数,比如你既然是个异步任务,如果是由外部的一个请求触发的,再这样的场景下,我们做全链路日志会比较麻烦,因为原生线程池是不会传递 jvm 参数的,所以需要我们封装一下,这样就可以方便的在日志系统中通过一个 logid 搜索全链路日志了。

    另一个好处是,自己封装的线程池,我们也可以方便做一些 feature 进去,比如动态扩容,缩容线程池,如果一开始都用了系统的,没有统一收口的话,就会比较麻烦
    zava
        9
    zava  
       2022-05-19 21:46:32 +08:00
    这么做明显有问题呀!增加偶然复杂度。要不就是作者没关注这块;要不就是有其他原因,但就算有其他原因,也没有在代码上体现出原因或意图,可读性明显有问题。这不,题主就被阔绕有疑惑,跑来问了。

    这代码要在我这里 review ,是会被我说的...
    gosidealone
        10
    gosidealone  
    OP
       2022-05-19 21:59:17 +08:00
    所以我觉得应该是作者可能没注意,谢谢大佬们的回复
    @mikicomo
    @zava
    @mmdsun
    dqzcwxb
        11
    dqzcwxb  
       2022-05-19 23:50:50 +08:00
    @gosidealone #3 1 使用了 @Async 的线程,但是只是走个过场而已
    2 的死锁和处理方案看这个 https://yanbin.blog/common-threadpool-vs-forkjoinpool/
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     932 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 20:06 PVG 04:06 LAX 12:06 JFK 15:06
    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