bonecp不具有回縮功能,即鏈接池持有鏈接以後,不會主動去釋放這些鏈接(即便這些鏈接始終處於空閒狀態),所以在使用一段時間以後,鏈接池會達到配置的最大值。java
這種方式必定程度上形成了資源的浪費。git
參考tomcat-jdbc的策略,每隔一段時間(可配置)會啓動定時任務掃描partition中的idle隊列,判斷idle鏈接數是否大於partition可持有的最小鏈接數,若是是,則啓動清理方法,將鏈接釋放掉。github
爲了達到這個目的,實現了ConnectionCleanThread類:sql
package com.jolbox.bonecp; import java.sql.SQLException; import java.util.concurrent.BlockingQueue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ConnectionCleanThread implements Runnable { private static final Logger logger = LoggerFactory.getLogger(ConnectionCleanThread.class); private ConnectionPartition partition; private BoneCP pool; protected ConnectionCleanThread(ConnectionPartition connectionPartition, BoneCP pool) { this.partition = connectionPartition; this.pool = pool; } @Override public void run() { BlockingQueue freeQueue = null; ConnectionHandle connection = null; //得到partition的大小 int partitionSize = this.partition.getAvailableConnections(); for (int i = 0; i < partitionSize; i++) { //獲得free鏈接的queue freeQueue = this.partition.getFreeConnections(); //若是空閒鏈接大於partition的最小容許鏈接數,回縮到最小容許鏈接數 while (freeQueue.size() > this.partition.getMinConnections()) { connection = freeQueue.poll(); connection.lock(); closeConnection(connection); connection.unlock(); } } } /** Closes off this connection * @param connection to close */ private void closeConnection(ConnectionHandle connection) { if (connection != null && !connection.isClosed()) { try { connection.internalClose(); } catch (SQLException e) { logger.error("Destroy connection exception", e); } finally { this.pool.postDestroyConnection(connection); connection.getOriginatingPartition().getPoolWatchThreadSignalQueue().offer(new Object()); // item being pushed is not important. } } } }
同時須要對核心類ConnectionHandle進行改造,加上鍊接的上鎖方法:tomcat
protected void lock() { lock.writeLock().lock(); } protected void unlock() { lock.writeLock().unlock(); }
在BoneCP類的構造器內加上該線程的定時任務:ide
/** * 空閒鏈接清理任務 */ private ScheduledExecutorService connectionCleanScheduler; ... this.connectionCleanScheduler = Executors.newScheduledThreadPool(this.config.getPartitionCount(), new CustomThreadFactory("BoneCP-connection-clean-thread"+suffix, true)); ... //按期啓動一個線程清理空閒鏈接 //add 2017-2-10 final Runnable connectionCleaner = new ConnectionCleanThread(connectionPartition, this); this.connectionCleanScheduler.scheduleAtFixedRate(connectionCleaner, this.config.getConnectionCleanTimeInSeconds(), this.config.getConnectionCleanTimeInSeconds(), TimeUnit.SECONDS);
通過實際測試,能夠在後臺自動的回收idle鏈接。post
如今只是實現了功能,各類狀況暫時沒有加入考慮,好比沒有判斷該鏈接是否應該被釋放。測試
bonecpthis