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实际上即实现对连接数组中每个元素的并发操作,无锁实现。
