一直不觉得什么样的代码逻辑才会在小并发下没问题,而在大并发下有问题,今天终于见到了。
今天做一个压力测试,刚刚开始,程序就无法响应了;小伙伴说,重启一个服务吧,我说,还是查查为啥吧,于是发现如下问题:
环境介绍:
- 数据库连接池,限制最多100个链接
- 代码中有一个方法设置了同步(无法多个线程同时执行到该代码,锁等待)
- JAVA多线程环境
代码逻辑为:
- begin 事务
- 执行同步方法
- 同步方法中可以需要执行sql语句,需要一个空闲的数据库连接(该逻辑比较深,不太容易注意到),如果获取不到数据库连接,就等待(如果非要加一个期限的话,实际上是无限期)
- 执行其他sql查询
- 结束
当100个请求同时执行到步骤1的时候,其中一个线程抢先进入了同步方法,但是不幸的是,虽然抢先进入了同步方法,但由于数据库连接已耗尽,只好等待;但是现在其它线程拿着数据库连接却由于等待在同步方法外而无法释放数据库连接,于是,死锁出现。。。
debug过程
由于bug是在高并发下出现的,不宜单步调试,只能从出错的状态中去分析。
第一步: jstack $pid
…. (有N多线程的堆栈就出来了)
第二步: 分析堆栈
很多线程被block,推测:应该有个线程(的堆栈)和别人不太一样; 果然如此
第三步: 参照堆栈和代码,分析得到结果
解决办法:
。。。