@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
1
dqzcwxb 2022-05-19 20:20:47 +08:00
|
2
mmdsun 2022-05-19 20:30:16 +08:00 via iPhone
|
3
gosidealone OP |
4
gosidealone OP @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
|
7
mikicomo 2022-05-19 21:00:49 +08:00
另外,sendMsgBatch 方法中循环调用了 this.sendTemplateMsg ,注意同个类下,两个 async 方法相互调用时,@async 会失效,如果作者没有在 sendMsgBatch 另起 TaskExcutor 的话,可能和它的本意不符了( sendMsgBatch 本身虽然是异步,但是内部的循环执行降级为了同步,线程也占用了很久),现在作者的这种写法,是把压力都丢给了 TaskExcutor ,让他慢慢去执行,@async 开出的线程池立马就释放了
道理是这个道理,但是这么写,其实也不是很建议就是了 |
8
mikicomo 2022-05-19 21:08:51 +08:00
这里展开说一下,其实自己项目使用自己封装过后的线程池是个好习惯,不过如果只是为了控制线程池个数的话,那倒也大可不必,原生的配置也蛮好。
一般我们遇到自己封装线程池的场景,主要是为了传递一些系统中的参数,比如你既然是个异步任务,如果是由外部的一个请求触发的,再这样的场景下,我们做全链路日志会比较麻烦,因为原生线程池是不会传递 jvm 参数的,所以需要我们封装一下,这样就可以方便的在日志系统中通过一个 logid 搜索全链路日志了。 另一个好处是,自己封装的线程池,我们也可以方便做一些 feature 进去,比如动态扩容,缩容线程池,如果一开始都用了系统的,没有统一收口的话,就会比较麻烦 |
9
zava 2022-05-19 21:46:32 +08:00
这么做明显有问题呀!增加偶然复杂度。要不就是作者没关注这块;要不就是有其他原因,但就算有其他原因,也没有在代码上体现出原因或意图,可读性明显有问题。这不,题主就被阔绕有疑惑,跑来问了。
这代码要在我这里 review ,是会被我说的... |
10
gosidealone OP |
11
dqzcwxb 2022-05-19 23:50:50 +08:00
@gosidealone #3 1 使用了 @Async 的线程,但是只是走个过场而已
2 的死锁和处理方案看这个 https://yanbin.blog/common-threadpool-vs-forkjoinpool/ |