背景
现在的项目使用了阿里druid jdbc连接池,有个使用场景要测试一下在高并发查询的情况下关闭连接池会不会存在问题,比如内存泄露等情况。
当时一个同事写了一个单元测试,这个单元测试大致做的事情是开很多线程不断获取连接查询,然后一个线程在一定查询后生成新的连接池替换旧的连接池,并关闭旧的连接池,进行多次循环。本来这个测试的目的是执行一个长的测试任务看看会不会有内存泄露的情况,但是后面发现有些线程都卡在了下图显示的地方,测试任务无法结束。
模拟的测试代码
下面的测试代码可以在最新版本的druid(1.1.21)上也能重现这个问题。
要用这个测试重现问题不要设置maxWait,这也是为什么这个bug在生产上不重要的原因,是因为生产都会设置maxWait,设置maxWait可以避免这个问题,当时忘记设置才发现问题。后面之所以要费力气查找这个问题的原因纯粹是因为好奇。
下面的测试代码根据机器的性能能否复现有所不同,机器性能越好,加大线程数量或循环次数才可能出现。
public class DruidTest {
//druid配置参数,使用模拟的jdbc driver
private String jdbcUrl = "jdbc:fake:dragoon_v25masterdb";
private String user = "dragoon25";
private String password = "dragoon25";
private String driverClass = "com.alibaba.druid.mock.MockDriver";
private int initialSize = 2;
private int minPoolSize = 5;
private int maxActive = 10;
private String validationQuery = "SELECT 1";
private int threadCount = 50;
private int executeCount = 100;
final int LOOP_COUNT = 1000;
private AtomicReference<DruidDataSource> ds = new AtomicReference<>();
@Test
public void neverStopTest() throws Exception {
Properties config = new Properties();
config.put(PROP_MAXACTIVE, maxActive + "");
config.put(PROP_INITIALSIZE, initialSize + "");
config.put(PROP_MINIDLE, minPoolSize + "");
config.put(PROP_VALIDATIONQUERY, validationQuery);
config.put(PROP_TESTWHILEIDLE, "true");
config.put(PROP_URL, jdbcUrl);
config.put(PROP_USERNAME, user);
config.