mysql_query 堆栈毁坏 多线程_多线程并发落库遇到的线程问题

为了提供落库效率,项目组决定采用多线程并发落库,但是出了问题,数据一条没有落下来。

1:怀疑时mysql数据库发生了死锁

使用这个命令查看是否有表被锁住了,发现没有表被锁

025622418b0f90964dba7340806d5cd6.png

2:于是查看线程池中的10条线程在做什么

使用jstack查看进程的堆栈信息

e87fe4b61c47dcad7180a043e2a7f938.png

线程池的最大线程数和核心线程数配的都是10 ,队列使用LinedListQueue对列,长度10240000

发现线程池中的10个线程都阻塞了,而且第一个创建的线程也没有释放,而且和数据源也没有关系,不可能是连接没有释放的问题。

3:于是想review一下代码,反编译一下源码,发现mapper中新接口没有,那为什么日志中没有报错呢?

于是看了一下异步落库的代码

a01959e25a7dedef38efc2c93764b2e9.png

异步落库使用的线程池的submit方法,然后百度了一下发现submit方法内部抛异常是不是抛出来的,而且线程会阻塞

4:于是自己做个demo测试一下

写一个线程池,使用submit提交task,虽然run内部抛出了异常,但是并没有在控制台打印

27e454aff1215d40f3f39e4ff21ea268.png

执行结果:

280e35dc1e7b216c10e0631f03644662.png

但是把submit改成execute后,在执行,就可以在控制台打印了

bcf69dd7e9980e51e1461a0bed178588.png

9df3b15ff6876a62b4c90c3f91da4fef.png

下面来看一下submit内部的代码:

把task任务封装到FutureTask中

c2ace437def7b098f969f57159ab22e4.png

FutureTask继承RunnableFuture类

d3af62c45148002f3c8a97c32dad63f0.png

RunnableFuture有继承Runnable  Future接口,所以FutureTask也是一个Runnable的类

0d2e0e921e6f615bff982a30eeffa179.png

调用到线程池ThreadPoolExecutor的execute方法

945e9df762d628ac1479583f087b45d3.png

最后会调用Worker的run方法,因为DefaultThreadFactory创建线程对象时,Workder对象作为runnable参数传了进去

worker的run方法会调到runWorker方法,这里的firstTask就是FutureTask

8ce1e2fed2ecbf2c85c23112ca4fcecf.png

我们看一下FutureTask的run方法,在这里很明显,如果call方法内部抛异常就会捕获到,然后封装到outcome结果里,其实就是

封装到返回的结果Future里了。

c0d9821cbf351ed037fdd6e9a156dfda.png

fce7f11dd815fddc8844571dd2bf7344.png

如果线程池调用execute时,就没有先把task封装到FutureTask里面,而是直接调用execute方法,所以异常

就直接抛出来了,没有捕捉。

如果我们把结果赋值给future,然后get,才会把异常抛出来:

75e4a0f60a5aaac4bed8eb988ba37a35.png

e7b6d4d2a2e6d1571ef4ae8ef541dad4.png

再来看一下线程池内部维护的线程

6c43378ad81d425c730435f05f505b42.png

65aefb534689b25188cb143bd9de6064.png

如果使用submit,在FutureTask中就会把异常捕获,然后封装到future中,线程池中的线程不会销毁。

如果换成execute时,异常会抛出,线程池内的线程会销毁,然后重新创建:

a6dc2911c7a516811369d26cdf6fd3ba.png

3fdb3bdb5d04b66c2ecce4555aaf77ab.png

问题也解决了,验证结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值