我们知道semaphore是一个共享型的同步机制,它的作用类似于一辆公交车有限定坐多少人,每次只有买票的人才能上车(acquire()获得许可),但是车的容量又是有限的,所以当达到一定容量的时候就后面的人就阻塞住上不来了,只能等车上有人下车(release()释放许可)。而这不正是数据库连接池的特性吗,像Druid,C3P0都是类似这样的机制。初始化固定的链接数量,当连接被消耗完毕时无法获取连接,当有SQL执行完毕连接被释放时,其他又可以进行连接。
Connect类
package niukewang;
import java.util.concurrent.TimeUnit;
public class Connect {
private static int count = 1;
private int id = count++;
public Connect(){
//假设打开一个连接需要耗费1秒
try {
TimeUnit.MICROSECONDS.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public String toString(){
return "#"+id+"#";
}
}
DatabaseLink类
package niukewang;
import java.util.concurrent.Semaphore;
import org.omg.CORBA.PUBLIC_MEMBER;
public class DataBaselink {
//连接池大小
private int size;
//当前数据库可用数
private int available;
//数据库连接集合
private Connect[] connects;
//连接状态
private boolean[] connectFlag;
//信号量对象
private Semaphore semaphore;
//初始化连接池大小
public DataBaselink(int size){
this.size = size;
this.available = size;
//信号量初始值为10,每成功进行一次acquire()操作,信号数减1,release()操作,信号数加1
semaphore = new Semaphore(size,true);
connects = new Connect[size];
connectFlag = new boolean[size];
initConnects();
}
//数据库初始化
private void initConnects() {
for (int i = 0; i < this.size; i++) {
connects[i] = new Connect();
}
}
//获得某个数据库连接,采用semaphore来控制
public Connect openConnect() throws InterruptedException{
//请求许可证,如何没有许可证,则一直阻塞
semaphore.acquire();
return getConnect();
}
//因为可能存在多个线程请求连接,所以应该设为synchronized
private synchronized Connect getConnect() {
for(int i=0;i<connectFlag.length;i++)
{
//找到没有被使用的连接
if(connectFlag[i]== false)
{
//将该连接设为被连接了
connectFlag[i] = true;
available--;
System.out.println("【"+Thread.currentThread().getName()+"】以获取连接 剩余连接数:" + available);
//获得这个连接
return connects[i];
}
}
return null;
}
//释放连接
public synchronized void releaseConnect(Connect connect)
{
for (int i = 0; i < connectFlag.length; i++) {
if(connect == connects[i])
{
connectFlag[i] = false;
available++;
System.out.println("【"+Thread.currentThread().getName()+"】已释放连接 剩余连接数:" + available);
//信号量-1
semaphore.release();
}
}
}
}
TestThread类
package niukewang;
public class TestThread implements Runnable {
private static DataBaselink pool = new DataBaselink(10);
@Override
public void run() {
try {
//打开一个连接
Connect connect = pool.openConnect();
Thread.sleep(100);
pool.releaseConnect(connect);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
Thread thread = new Thread(new TestThread());
thread.start();
}
}
}
运行结果
【Thread-1】以获取连接 剩余连接数:9
【Thread-5】以获取连接 剩余连接数:8
【Thread-4】以获取连接 剩余连接数:7
【Thread-3】以获取连接 剩余连接数:6
【Thread-2】以获取连接 剩余连接数:5
【Thread-0】以获取连接 剩余连接数:4
【Thread-8】以获取连接 剩余连接数:3
【Thread-9】以获取连接 剩余连接数:2
【Thread-6】以获取连接 剩余连接数:1
【Thread-7】以获取连接 剩余连接数:0
【Thread-7】已释放连接 剩余连接数:1
【Thread-1】已释放连接 剩余连接数:2
【Thread-5】已释放连接 剩余连接数:3
【Thread-4】已释放连接 剩余连接数:4
【Thread-3】已释放连接 剩余连接数:5
【Thread-2】已释放连接 剩余连接数:6
【Thread-0】已释放连接 剩余连接数:7
【Thread-8】已释放连接 剩余连接数:8
【Thread-19】以获取连接 剩余连接数:7
【Thread-6】已释放连接 剩余连接数:8
【Thread-16】以获取连接 剩余连接数:7
【Thread-9】已释放连接 剩余连接数:8
【Thread-15】以获取连接 剩余连接数:7
【Thread-17】以获取连接 剩余连接数:6
【Thread-14】以获取连接 剩余连接数:5
【Thread-12】以获取连接 剩余连接数:4
【Thread-13】以获取连接 剩余连接数:3
【Thread-11】以获取连接 剩余连接数:2
【Thread-10】以获取连接 剩余连接数:1
【Thread-18】以获取连接 剩余连接数:0
【Thread-15】已释放连接 剩余连接数:1
【Thread-17】已释放连接 剩余连接数:2
【Thread-16】已释放连接 剩余连接数:3
【Thread-19】已释放连接 剩余连接数:4
【Thread-13】已释放连接 剩余连接数:5
【Thread-18】已释放连接 剩余连接数:6
【Thread-11】已释放连接 剩余连接数:7
【Thread-14】已释放连接 剩余连接数:8
【Thread-12】已释放连接 剩余连接数:9
【Thread-10】已释放连接 剩余连接数:10