/** Executor service for obtaining a connection in an asynchronous fashion. */ private ExecutorService asyncExecutor; /** * Constructor. * @param config Configuration for pool * @throws SQLException on error */ public BoneCP(BoneCPConfig config) throws SQLException { ...... //在构造函数中初始化 this.asyncExecutor = Executors.newCachedThreadPool(); ...... } /** Obtain a connection asynchronously by queueing a request to obtain a connection in a separate thread. * * Use as follows:<p> * Future<Connection> result = pool.getAsyncConnection();<p> * ... do something else in your application here ...<p> * Connection connection = result.get(); // get the connection<p> * * @return A Future task returning a connection. */ public Future<Connection> getAsyncConnection(){ return this.asyncExecutor.submit(new Callable<Connection>() { public Connection call() throws Exception { return getConnection(); }}); }
2、releaseHelper 用于关闭Connection对象的线程池,该池程池中的线程为守护线程(Daemon Thread)
/** pointer to the thread containing the release helper threads. */ private ExecutorService releaseHelper; /** * Constructor. * @param config Configuration for pool * @throws SQLException on error */ public BoneCP(BoneCPConfig config) throws SQLException { ...... //Gets number of release-connection helper threads to create per partition int helperThreads = config.getReleaseHelperThreads(); this.releaseHelperThreadsConfigured = helperThreads > 0; //If set to true, config has specified the use of statement release helper threads. this.statementReleaseHelperThreadsConfigured = config.getStatementReleaseHelperThreads() > 0; this.config = config; String suffix = ""; if (config.getPoolName()!=null) { suffix="-"+config.getPoolName(); } if (this.releaseHelperThreadsConfigured){ this.releaseHelper = Executors.newFixedThreadPool(helperThreads*config.getPartitionCount(), new CustomThreadFactory("BoneCP-release-thread-helper-thread"+suffix, true)); } ...... }
如果用户设置了以独立线程来关闭Connection对象,才创建该线程池。
ThreadFactory用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。
public interface ThreadFactory { /** * Constructs a new {@code Thread}. Implementations may also initialize * priority, name, daemon status, {@code ThreadGroup}, etc. * * @param r a runnable to be executed by new thread instance * @return constructed thread, or {@code null} if the request to * create a thread is rejected */ Thread newThread(Runnable r); }CustomThreadFactory为BoneCP里对ThreadFactory的一个实现,并可设置线程是否为守护线程(Daemon Thread):
package com.jolbox.bonecp; ...... public class CustomThreadFactory implements ThreadFactory, UncaughtExceptionHandler { public CustomThreadFactory(String threadName, boolean daemon){ this.threadName = threadName; this.daemon = daemon; } public Thread newThread(Runnable r) { Thread t = new Thread(r, this.threadName); t.setDaemon(this.daemon); t.setUncaughtExceptionHandler(this); return t; } ...... }3、keepAliveScheduler 该线程池用于定期地测试connection的活性,即用它发送一条简单的SQL,并关闭故障的Connection,每个分区一个线程,此线程池中的线程也为守护线程。
/** Handle to factory that creates 1 thread per partition that periodically wakes up and performs some * activity on the connection. */ private ScheduledExecutorService keepAliveScheduler; this.keepAliveScheduler = Executors.newScheduledThreadPool(config.getPartitionCount(), new CustomThreadFactory("BoneCP-keep-alive-scheduler"+suffix, true));newScheduledThreadPool创建一个大小无限的线程池,此线程池支持定时以及周期性执行任务的需求,相当于Timer。
if (config.getIdleConnectionTestPeriodInMinutes() > 0 || config.getIdleMaxAgeInMinutes() > 0){ final Runnable connectionTester = new ConnectionTesterThread(connectionPartition, this.keepAliveScheduler, this, config.getIdleMaxAge(TimeUnit.MILLISECONDS), config.getIdleConnectionTestPeriod(TimeUnit.MILLISECONDS), queueLIFO); long delayInMinutes = config.getIdleConnectionTestPeriodInMinutes(); if (delayInMinutes == 0L){ delayInMinutes = config.getIdleMaxAgeInMinutes(); } if (config.getIdleMaxAgeInMinutes() != 0 && config.getIdleConnectionTestPeriodInMinutes() != 0 && config.getIdleMaxAgeInMinutes() < delayInMinutes){ delayInMinutes = config.getIdleMaxAgeInMinutes(); } this.keepAliveScheduler.schedule(connectionTester, delayInMinutes, TimeUnit.MINUTES); }
如果用户没有设置了下面两个属性小于1就启动该线程池的任务:
/** Connections older than this are sent a keep-alive statement. */ private long idleConnectionTestPeriodInSeconds = 240*60; /** Maximum age of an unused connection before it is closed off. */ private long idleMaxAgeInSeconds = 60*60;
实例化一个ConnectionTesterThread类型的Runnable对象,该对象中也持有此线程池的引用,用于在run方法中启动下次任务,此对象的run方法负责对异常的Connection对象和超出闲置时间的对象进行close并定期给Connection对象发送简单SQL语句:
// send a keep-alive, close off connection if we fail. if (!this.pool.isConnectionHandleAlive(connection)){ closeConnection(connection); continue; }
4、maxAliveScheduler 该线程池用于给每个分区创建一个线程定期的检查Connection对象是否过期,此线程池中的线程也是守护线程
/** Handle to factory that creates 1 thread per partition that periodically wakes up and performs some * activity on the connection. */ private ScheduledExecutorService maxAliveScheduler; this.maxAliveScheduler = Executors.newScheduledThreadPool(config.getPartitionCount(), new CustomThreadFactory("BoneCP-max-alive-scheduler"+suffix, true));
如果用户设置了下面属性大于0则使用该线程池:
/** A connection older than maxConnectionAge will be destroyed and purged from the pool. */ private long maxConnectionAgeInSeconds = 0;
if (config.getMaxConnectionAgeInSeconds() > 0){ final Runnable connectionMaxAgeTester = new ConnectionMaxAgeThread(connectionPartition, this.maxAliveScheduler, this, config.getMaxConnectionAge(TimeUnit.MILLISECONDS), queueLIFO); this.maxAliveScheduler.schedule(connectionMaxAgeTester, config.getMaxConnectionAgeInSeconds(), TimeUnit.SECONDS); }先实例化一个ConnectionMaxAgeThread类型的Runnable对象,该对象定期的对超过maxConnectionAge类型的对象进行关闭:
if (connection.isExpired(currentTime)){ // kill off this connection closeConnection(connection); continue; }ConnectionMaxAgeThread对象中也对该线程池持有引用来启动下次全任务。
5、connectionsScheduler 该线程池用于观察每个分区,根据需要动态的创建新的Connection对象或者清理过剩的,也为守护线程
/** Executor for threads watching each partition to dynamically create new threads/kill off excess ones. */ private ExecutorService connectionsScheduler; this.connectionsScheduler = Executors.newFixedThreadPool(config.getPartitionCount(), new CustomThreadFactory("BoneCP-pool-watch-thread"+suffix, true)); // watch this partition for low no of threads this.connectionsScheduler.execute(new PoolWatchThread(connectionPartition, this));
6、closeConnectionExecutor 该线程池用于监控那些失败的close操作
/** Threads monitoring for bad connection requests. */ private ExecutorService closeConnectionExecutor; this.closeConnectionWatch = config.isCloseConnectionWatch(); if (this.closeConnectionWatch){ logger.warn(THREAD_CLOSE_CONNECTION_WARNING); this.closeConnectionExecutor = Executors.newCachedThreadPool(new CustomThreadFactory("BoneCP-connection-watch-thread"+suffix, true)); }
在getConection()方法中如果用户设置了下面属性则启用该线程:
/** If set to true, create a new thread that monitors a connection and displays warnings if application failed to * close the connection. */ protected boolean closeConnectionWatch = false;
if (this.closeConnectionWatch){ // a debugging tool watchConnection(result); }
/** Starts off a new thread to monitor this connection attempt. * @param connectionHandle to monitor */ private void watchConnection(ConnectionHandle connectionHandle) { String message = captureStackTrace(UNCLOSED_EXCEPTION_MESSAGE); this.closeConnectionExecutor.submit(new CloseThreadMonitor(Thread.currentThread(), connectionHandle, message, this.closeConnectionWatchTimeoutInMs)); }
// @Override public void run() { try { this.connectionHandle.setThreadWatch(Thread.currentThread()); // wait for the thread we're monitoring to die off. this.threadToMonitor.join(this.closeConnectionWatchTimeout); if (!this.connectionHandle.isClosed() && this.threadToMonitor.equals(this.connectionHandle.getThreadUsingConnection()) ){ logger.error(this.stackTrace); } } catch (Exception e) { // just kill off this thread if (this.connectionHandle != null){ // safety this.connectionHandle.setThreadWatch(null); } } }