您的当前位置:首页正文

p6spy打印sql日志线程不安全导致的生产问题

2024-11-11 来源:个人技术集锦

  首先说明下我这个标题可能起的不到位,其实我本次要介绍的是一次生产定位问题的思路及过程。

1.生产现象

   国庆前期发布了一个很小版本,大家都以为没什么问题,可是发布后生产出现了问题并且持续了两个小时以上,现象如下:
ERROR|org.hibernate.engine.jdbc.spi.SqlExceptionHelper|[SimpleAsyncTaskExecutor-52] Timeout: Pool empty. Unable to fetch a connection in 30 seconds, none available[size:150; busy:150; idle:0; lastwait:60000].
  最直接报错就是生产应用程序获取数据库连接无法正常获取,当时未进行定位问题的情况下只打印了线程栈快照,堆快照信息未保存,然后扩大数据库连接,最后重启,重启后无问题(当晚未留,第天定位)。

2.线程dump文件分析

这里涉及到信息安全问题,公司内网无法发送资料,所以本地再现了下,线程栈信息大致如下:

3.问题复现及验证

1.复现HashMap死循环
这里我参考了
代码如下:

package com.spring.test.deadmap;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

public class HashMapThread extends Thread {
    private static AtomicInteger ai = new AtomicInteger(0);
    private static Map<Integer, Integer> map = new HashMap<Integer, Integer>(1);

    public void run() {
        while (ai.get() < 100000) {
            map.put(ai.get(), ai.get());
            ai.incrementAndGet();
        }
    }
}
package com.spring.test.deadmap;

public class Test {
    public static void main(String[] args) {
        HashMapThread hmt0 = new HashMapThread();
        HashMapThread hmt1 = new HashMapThread();
        HashMapThread hmt2 = new HashMapThread();
        HashMapThread hmt3 = new HashMapThread();
        HashMapThread hmt4 = new HashMapThread();
        hmt0.start();
        hmt1.start();
        hmt2.start();
        hmt3.start();
        hmt4.start();
    }
}

使用低版本jdk较容易复现死循环,多试几次。
2.证明线程无法结束是因为HashMap存在环
    我们需要借助堆快照形成堆内实例dump文件,借助MAT进行分析当前HashMap.Entry[]数组中的Entry链表是否存在循环引用

Top