import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicIntegerArray;
public class TestPool {
public static void main(String[] args) throws InterruptedException {
Pool pool = new Pool(2);
for (int i = 0; i <5 ; i++) {
new Thread(()->{
//借连接
Connection connection = pool.borrow();
try {
//模拟连接使用
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
pool.free(connection);
}).start();
}
}
}
class Pool{
//1.连接池大小
private final int poolSize;
//2.连接数组
private Connection[] connections;
//3.连接状态数组:0表示空闲,1表示繁忙,这里用原子数组修饰,使得对其操作均是原子,保证线程安全,不需要在方法里手动实现线程安全
private AtomicIntegerArray states;
//4.构造方法
public Pool(int poolSize) {
this.poolSize = poolSize;
//poolSize确定,连接数组以及状态数组则确定
this.connections = new Connection[poolSize];
this.states = new AtomicIntegerArray(new int[poolSize]);
//初始化数组
for (int i=0;i<poolSize;i++){
connections[i] = new MockConnection();
}
}
//5.借出连接
public Connection borrow() throws InterruptedException {
while (true){
for (int i=0;i<poolSize;i++){
//获取空闲连接
if(states.get(i)==0){
if (states.compareAndSet(i,0,1)) {
return connections[i];
}
}
}
//如果没有空闲连接,调用该方法的当前线程进入等待状态
synchronized (this){
this.wait();
}
}
}
//6.归还连接
public void free(Connection conn){
for (int i = 0; i <poolSize ; i++) {
//找到需要归还的连接
if(connections[i]==conn){
//注意归还线程的情况下,该连接一定被当前线程持有,不会发生线程竞争,直接set规划即可
states.set(i,0);
synchronized (this){
this.notifyAll();//唤醒在当前对象上等待的所有线程
}
break;
}
}
}
}
class MockConnection implements Connection{
public MockConnection() {
super();
}
@Override functions..
}
几个实现细节需要注意:
- 连接状态的判断是通过一个状态数组实现的,数组中存储0-1,表示链接空闲or不可用
- 用Atomatic修饰数组,是要保证对数组的操作均是原子性操作,但不能保证线程安全,原子和线程安全是两码事。
- borrow()方法要while循环,为了能取到一份Connection对象,而如果一次for循环仍取不到,则要进入wait等待状态
- borrow()方法中的CAS操作,是解决多线程多次获取同一Connection对象问题,当某一线程的CAS操作无法执行,那么就获取不到该Connection对象。
- borrow()方法中的CAS实际上即实现对连接数组中每个元素的并发操作,无锁实现。