一、数据库连接池初始化
(1)、 如果设置了maxWait或者构造函数参数传入的为true,则创建的ReentrantLock为公平锁,否者为非公平锁
(2)、 如果设置了initialSize>=1,则会启动是创建initialSize个数数据库物理连接到线程池。
(3)、 如果没设置createScheduler则创建并启动数据库连接创建线程,如果没设置destroyScheduler则创建并启动数据库连接回收线程,如果timeBetweenLogStatsMillis>0则创建logstat线程。
二、获取数据库连接
(1)、 如果当前数据库连接池有可用连接,则直接获取,否者如果设置createScheduler则开启一个新线程去创建物理连接,否者发送发送signal信号唤醒连接创建线程创建数据库物理连接,这种情况有分pollLast和takeLast,区别在于前者设置max
wait超时时间,如果在时间内还没获取链接则返回null,后者则一直等待连接创建。
三、回收数据库连接
(1)、 在调用conn.close时候会回收当前连接到线程池
四、创建数据库连接线程
(1)、此图createScheduler=null的情况,为null从上面知道在初始化时候会新建
一个数据库连接创建线程。
五、连接池同步策略
实际上是个生产者消费者模式,生产者是连接创建线程和连接回收线程,消费者是获取连接的线程。
首先列下同步需要的条件变量和锁:
//独占锁(用来控制同是只有一个线程访问线程池),根据lockFair分为公平和非公平锁lock = new ReentrantLock(lockFair);//用来对消费和生成线程做同步notEmpty = lock.newCondition();empty = lock.newCondition();//共享资源,线程池是一个数组connections = new DruidConnectionHolder[maxActive];
消费者(获取数据库连接线程):
DruidConnectionHolder pollLast(){DruidConnectionHolder holder;try {//加独占锁lock.lockInterruptibly();} catch (InterruptedException e) {connectErrorCount.incrementAndGet();throw new SQLException("interrupt", e);}try {//通知连接创建线程,创建数据库连接empty.signal();//等待连接创建线程或者连接回收线程发送信号estimate = notEmpty.awaitNanos(estimate);//获取链接,并返回decrementPoolingCount();holder = connections[poolingCount];connections[poolingCount] = null;}finally{//释放独占锁lock.unlock();}holder.incrementUseCount();DruidPooledConnection poolalbeConnection = new DruidPooledConnection(holder);return poolalbeConnection;
}
生产者(连接创建线程):
public void run(){try {//独占锁lock.lockInterruptibly();} catch (InterruptedException e2) {break;}try {// 必须存在线程等待,才创建连接if (poolingCount >= notEmptyWaitThreadCount) {empty.await();//会释放当前独占锁}// 防止创建超过maxActive数量的连接if (activeCount + poolingCount >= maxActive) {empty.await();//会释放当前独占锁}} finally {lock.unlock();}Connection connection = null;try {//创建物理链接connection = createPhysicalConnection();} catch (SQLException e) {。。。。} catch (RuntimeException e) {。。。。} catch (Error e) {。。。。}lock.lock();try {//连接入池connections[poolingCount] = holder;incrementPoolingCount();if (poolingCount > poolingPeak) {poolingPeak = poolingCount;poolingPeakTime = System.currentTimeMillis();}//发出信号,激活消费线程notEmpty.signal();notEmptySignalCount++;} finally {lock.unlock();}}
生产者(数据库连接回收线程):
protected void recycle(DruidPooledConnection pooledConnection){lock.lockInterruptibly();try {activeCount--;closeCount++;connections[poolingCount] = e;incrementPoolingCount();if (poolingCount > poolingPeak) {poolingPeak = poolingCount;poolingPeakTime = lastActiveTimeMillis;}//激活消费线程notEmpty.signal();notEmptySignalCount++; recycleCount++;} finally {lock.unlock();}
}