bonecp回縮功能實現

原由

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

如今只是實現了功能,各類狀況暫時沒有加入考慮,好比沒有判斷該鏈接是否應該被釋放。測試

GitHub地址

bonecpthis

相關文章
相關標籤/搜索