class SourceGetConn implements Runnable {
private ComboPooledDataSource source = null;
public SourceGetConn(ComboPooledDataSource source) {
this.source = source;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
source.getConnection();
System.out.println("I get a Connection! I am in " + Thread.currentThread().getName());
} catch (InterruptedException | SQLException e) {
e.printStackTrace();
}
}
}
}
class DestGetConn implements Runnable {
private ComboPooledDataSource postgres = null;
public DestGetConn(ComboPooledDataSource source) {
this.postgres = source;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
postgres.getConnection();
System.out.println("I get a Connection! I am in " + Thread.currentThread().getName());
} catch (InterruptedException | SQLException e) {
e.printStackTrace();
}
}
}
} 将一个
ComboPooledDataSource实例,传给两个线程分别getConnection,getConnection的过程没有加锁的情况下是可以运行的,完全没有问题。
3.经过测试发现同一个数据源的两个
ComboPooledDataSource实例,getConnection方法不加锁的情况下,也是没有问题的。
稍微总结一下:
C3P0在一个ComboPooledDataSource实例的getConnection方法是线程安全的
C3P0在一个数据源的多个ComboPooledDataSource实例的getConnection方法也是线程安全的
C3P0在多个数据源的多个ComboPooledDataSource不同时调用getConnection的情况下,不会发生死锁(基于概率,若干时间之后,肯定会发生死锁)
C3P0在多个数据源的多个ComboPooledDataSource实例的getConnection方法同时(相邻的两行代码)调用时,会发生死锁现象,如1中所述
4.总结:
属于不同数据源的多个ComboPooledDataSource实例的getConnection方法调用要互斥
测试代码如下:
package com.highgo.test.c3p0deadlock;
import java.sql.SQLException;
import java.util.concurrent.locks.ReentrantLock;
import com.mchange.v2.c3p0.ComboPooledDataSource;
//加锁source个postgre的ComboPooledDataSource的getConnection用一个锁
public class Test2 {
public static void main(String[] args) throws InterruptedException {
ComboPooledDataSource source = new ComboPooledDataSource("source");
ComboPooledDataSource source2 = new ComboPooledDataSource("source");
ComboPooledDataSource postgres = new ComboPooledDataSource("postgres");
ComboPooledDataSource postgres2 = new ComboPooledDataSource("postgres");
ReentrantLock lock = new ReentrantLock();
new Thread(new SourceGetConn2(source, lock), "source").start();
new Thread(new SourceGetConn2(source2, lock), "source2").start();
Thread.sleep(1000);
new Thread(new DestGetConn2(postgres, lock), "postgres").start();
new Thread(new DestGetConn2(postgres2, lock), "postgres2").start();
}
}
class SourceGetConn2 implements Runnable {
private ComboPooledDataSource source = null;
private ReentrantLock lock;
public SourceGetConn2(ComboPooledDataSource source, ReentrantLock lock) {
this.source = source;
this.lock = lock;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
lock.lock();
source.getConnection();
lock.unlock();
System.out.println("I get a Connection! I am in " + Thread.currentThread().getName());
} catch (InterruptedException | SQLException e) {
e.printStackTrace();
}
}
}
}
class DestGetConn2 implements Runnable {
private ComboPooledDataSource postgre