最近公司要求基於阿里的DruidDataSource來做一個連接池監控 , 正好之前沒有看過DruidDataSource的源碼 , 便自己看了四個多小時寫了一些自己的理解 , 給大家分享一下 , 如果有什么錯誤 , 歡迎指出!!!
DruidDataSource主要用到的是ReentrantLock鎖,還有 notEmpty empty兩個條件,生產連接與消費連接的線程在兩個條件上等待與喚醒。
1創建連接
連接太多了的時候,在empty條件上等待,就是等空了再運行
1 // 防止創建超過maxActive數量的連接 2 if (activeCount + poolingCount >= maxActive) { 3 empty.await(); 4 continue; 5 } 6 7 connection = createPhysicalConnection(); 8 setFailContinuous(false); 9 10 boolean result = put(connection);
后面是創建一個物理連接,然后put一下,這個put是放池子中,主要下面幾句:
1 holder = new DruidConnectionHolder(DruidDataSource.this, physicalConnectionInfo); 2 connections[poolingCount] = holder; 3 incrementPoolingCount(); 4 notEmpty.signal(); 5 notEmptySignalCount++;
2使用連接
DruidConnectionHolder takeLast()之中,當poolingCount中數量為0時等待。
正好說明使用連接的線程,當連接沒有時,就等待。如果池中有連接就執行下面的語句:
1 decrementPoolingCount(); 2 DruidConnectionHolder last = connections[poolingCount];//拿走池中最后一個 3 connections[poolingCount] = null;//最后一個賦值成null
獲取鏈接的主要方法getPooledConnection()中調用takeLast(),又調用getConnection(),
這里面又是插入了過濾鏈來統計。filterChain.dataSource_connect()參數中有this,說明它把自己傳進去了,
說明這個filterChain並不從屬於任何datasource,可以是這個數據源,也可以是那個數據源。具體過濾哪個,臨時傳入。
3減少連接
在創建連接線程附近還有一個DestroyConnectionThread()
跟蹤里面,有destroyTask.run();----->shrink(true);連接空閑的太多了就縮小。
在shrink()方法中,重點有下面的語句:
1 final int checkCount = poolingCount - minIdle;//池中的數量-最小空閑數量 2 3 for (DruidConnectionHolder item : evictList) {//可回收的DruidConnectionHolder 4 Connection connection = item.getConnection(); 5 JdbcUtils.close(connection); 6 destroyCount.incrementAndGet(); 7 }
4init()
創建線程與收縮線程都是由void init()來調用的,主要代碼如下。
1 connections = new DruidConnectionHolder[maxActive];//新建連接池,個數是最大活動連接數maxActive。 2 3 for (int i = 0, size = getInitialSize(); i < size; ++i) {//放入連接池中連接 4 PhysicalConnectionInfo pyConnectInfo = createPhysicalConnection(); 5 DruidConnectionHolder holder = new DruidConnectionHolder(this, pyConnectInfo); 6 connections[poolingCount] = holder; 7 incrementPoolingCount(); 8 } 9 10 createAndLogThread(); 11 createAndStartCreatorThread();//創建連接的線程,一直在工作,池子滿了就是等待狀態。 12 createAndStartDestroyThread();//收縮池子的線程,一直在工作。 13 14 15 initedLatch.await();//主線程在計數器為0前一直等待。 16 17 init = true;
這里有一個知識點。
1 CountDownLatch initedLatch = new CountDownLatch(2);
就叫倒計時同步器。當前同步數為2,在變成0后,主線程才能運行,否則一直等待中。
在創建連接與收縮池子的線程中都有initedLatch.countDown();,
一共正好兩個,主線程就是等待上面兩個線程都運行了才運行,才置init狀態標識為true。
