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