public void initializePoolCleaner(PoolConfiguration properties) {
//if the evictor thread is supposed to run, start it now
if (properties.isPoolSweeperEnabled()) {
poolCleaner = new PoolCleaner(this, properties.getTimeBetweenEvictionRunsMillis());
poolCleaner.start();
} //end if
}
PoolCleaner(ConnectionPool pool, long sleepTime) {
this.pool = new WeakReference<>(pool);
this.sleepTime = sleepTime;
if (sleepTime <= 0) {
log.warn("Database connection pool evicter thread interval is set to 0, defaulting to 30 seconds");
this.sleepTime = 1000 * 30;
} else if (sleepTime < 1000) {
log.warn("Database connection pool evicter thread interval is set to lower than 1 second.");
}
}
//if we get here, see if we need to create one
//this is not 100% accurate since it doesn't use a shared
//atomic variable - a connection can become idle while we are creating
//a new connection
if (size.get() < getPoolProperties().getMaxActive()) {
//atomic duplicate check
if (size.addAndGet(1) > getPoolProperties().getMaxActive()) {
//if we got here, two threads passed through the first if
size.decrementAndGet();
} else {
//create a connection, we're below the limit
return createConnection(now, con, username, password);
}
} //end if
//calculate wait time for this iteration
long maxWait = wait;
5.1 创建PooledConnection,保存用户密码
5.2 PooledConnection.connect连接,如果已经release抛出异常:“A connection once released, can’t be reestablished.”
创建失败则抛出异常:“Unable to create initial connections of pool.”
遍历初始化连接池调用returnConnection
finally {
//return the members as idle to the pool
for (int i = 0; i < initialPool.length; i++) {
if (initialPool[i] != null) {
try {this.returnConnection(initialPool[i]);}catch(Exception x){/*NOOP*/}
} //end if
} //for
} //catch
returnConnection:return the members as idle to the pool,Returns a connection to the pool
如果已经close则释放连接
如果入参PooledConnection con不为空,returnedCount递增
如果连接已经被标注为被怀疑超时的对象,日志开启的情况下则打印日志
busy队列移除该连接成功,如果shouldClose则释放并打印debug日志:“Connection [”+con+"] will be closed and not returned to the pool."
如果shouldClose为false
protected boolean shouldClose(PooledConnection con, int action) {
if (con.getConnectionVersion() < getPoolVersion()) return true;
if (con.isDiscarded()) return true;
if (isClosed()) return true;
if (!con.validate(action)) return true;
if (!terminateTransaction(con)) return true;
if (con.isMaxAgeExpired()) return true;
else return false;
}
if (((idle.size()>=poolProperties.getMaxIdle()) && !poolProperties.isPoolSweeperEnabled()) || (!idle.offer(con))) {
if (log.isDebugEnabled()) {
log.debug("Connection ["+con+"] will be closed and not returned to the pool, idle["+idle.size()+"]>=maxIdle["+poolProperties.getMaxIdle()+"] idle.offer failed.");
}
release(con);
}
public boolean isPoolSweeperEnabled() {
boolean timer = getTimeBetweenEvictionRunsMillis()>0;
boolean result = timer && (isRemoveAbandoned() && getRemoveAbandonedTimeout()>0);
result = result || (timer && getSuspectTimeout()>0);
result = result || (timer && isTestWhileIdle() && getValidationQuery()!=null);
result = result || (timer && getMinEvictableIdleTimeMillis()>0);
return result;
}
busy队列移除该连接失败,释放连接,打印debug日志:“Connection [”+con+"] will be closed and not returned to the pool, busy.remove failed."
初始化完成
DataSource.ConnectionPool.getConnection
从连接池中获取连接
public Connection getConnection() throws SQLException {
//check out a connection
PooledConnection con = borrowConnection(-1,null,null);
return setupConnection(con);
}
public boolean offer(E e) {
//during the offer, we will grab the main lock
final ReentrantLock lock = this.lock;
lock.lock();
ExchangeCountDownLatch<E> c = null;
try {
//check to see if threads are waiting for an object
if (waiters.size() > 0) {
//if threads are waiting grab the latch for that thread
c = waiters.poll();
//give the object to the thread instead of adding it to the pool
c.setItem(e);
if (isLinux) c.countDown();
} else {
//we always add first, so that the most recently used object will be given out
items.addFirst(e);
}
} finally {
lock.unlock();
}
//if we exchanged an object with another thread, wake it up.
if (!isLinux && c!=null) c.countDown();
//we have an unbounded queue, so always return true
return true;
}
public Future<E> pollAsync() {
Future<E> result = null;
final ReentrantLock lock = this.lock;
//grab the global lock
lock.lock();
try {
//check to see if we have objects in the queue
E item = items.poll();
if (item==null) {
//queue is empty, add ourselves as waiters
ExchangeCountDownLatch<E> c = new ExchangeCountDownLatch<>(1);
waiters.addLast(c);
//return a future that will wait for the object
result = new ItemFuture<>(c);
} else {
//return a future with the item
result = new ItemFuture<>(item);
}
} finally {
lock.unlock();
}
return result;
}
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
E result = null;
final ReentrantLock lock = this.lock;
//acquire the global lock until we know what to do
lock.lock();
try {
//check to see if we have objects
result = items.poll();
if (result==null && timeout>0) {
//the queue is empty we will wait for an object
ExchangeCountDownLatch<E> c = new ExchangeCountDownLatch<>(1);
//add to the bottom of the wait list
waiters.addLast(c);
//unlock the global lock
lock.unlock();
boolean didtimeout = true;
InterruptedException interruptedException = null;
try {
//wait for the specified timeout
didtimeout = !c.await(timeout, unit);
} catch (InterruptedException ix) {
interruptedException = ix;
}
if (didtimeout) {
//if we timed out, or got interrupted
// remove ourselves from the waitlist
lock.lock();
try {
waiters.remove(c);
} finally {
lock.unlock();
}
}
//return the item we received, can be null if we timed out
result = c.getItem();
if (null!=interruptedException) {
//we got interrupted
if ( null!=result) {
//we got a result - clear the interrupt status
//don't propagate cause we have removed a connection from pool
Thread.interrupted();
} else {
throw interruptedException;
}
}
} else {
//we have an object, release
lock.unlock();
}
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
return result;
}