在初始化JDBC Connection Pool的时候出现了死锁。
经分析,该死锁出现的前提为:
1. Load 不同的JDBC Driver;
2. 要在不同的Thread中。
代码如下:
public class PoolTest {
public static void main(String[] args) throws Exception {
boolean dead = true;
if (!dead) {
Class.forName("net.sourceforge.jtds.jdbc.Driver");
Class.forName("org.h2.Driver");
}
Thread a = new Thread(new PoolThreadA());
Thread b= new Thread(new PoolThreadB());
a.start();
b.start();
}
}
class PoolThreadA implements Runnable {
@Override
public void run() {
DataSource ds = initDataSource();
try {
Connection c = ds.getConnection();
} catch (Exception e) {
}
}
private static DataSource initDataSource() {
String connectionString = "jdbc:jtds:sqlserver://10.16.33.204:1433;databaseName=master";
PoolProperties p = new PoolProperties();
p.setUrl(connectionString);
p.setDriverClassName("net.sourceforge.jtds.jdbc.Driver");
p.setUsername("sa");
p.setPassword("Oliver123");
p.setJmxEnabled(true);
p.setTestWhileIdle(false);
p.setTestOnBorrow(true);
p.setValidationQuery("SELECT 1");
p.setTestOnReturn(false);
p.setValidationInterval(0);
p.setTimeBetweenEvictionRunsMillis(30000);
p.setMinIdle(100);
p.setInitialSize(10);
p.setMaxWait(10000);
p.setRemoveAbandonedTimeout(60);
p.setMinEvictableIdleTimeMillis(30000);
p.setMinIdle(10);
p.setMaxActive(0);
p.setLogAbandoned(true);
p.setRemoveAbandoned(true);
p.setJdbcInterceptors(
"org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"+
"org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;"
);
DataSource datasource = new DataSource();
datasource.setPoolProperties(p);
return datasource;
}
}
class PoolThreadB implements Runnable{
@Override
public void run() {
DataSource ds = initDataSource();
try {
Connection c = ds.getConnection();
} catch (Exception e) {
}
}
private static DataSource initDataSource() {
String connectionString = "jdbc:h2:mem:test;MVCC=TRUE;MODE=Oracle;MULTI_THREADED=TRUE;DB_CLOSE_DELAY=-1";
PoolProperties p = new PoolProperties();
p.setUrl(connectionString);
p.setDriverClassName("org.h2.Driver");
p.setUsername("sa");
p.setPassword("");
p.setJmxEnabled(true);
p.setTestWhileIdle(false);
p.setTestOnBorrow(true);
p.setValidationQuery("SELECT 1");
p.setTestOnReturn(false);
p.setValidationInterval(0);
p.setTimeBetweenEvictionRunsMillis(30000);
p.setMinIdle(100);
p.setInitialSize(10);
p.setMaxWait(10000);
p.setRemoveAbandonedTimeout(60);
p.setMinEvictableIdleTimeMillis(30000);
p.setMinIdle(10);
p.setMaxActive(0);
p.setLogAbandoned(true);
p.setRemoveAbandoned(true);
p.setJdbcInterceptors(
"org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"+
"org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;"
);
DataSource datasource = new DataSource();
datasource.setPoolProperties(p);
return datasource;
}
}
比如 https://m.oschina.net/blog/289120
解决方法是把Load Class的地方放到线程外面。