DataSourceFactory -> DataSource -> 初始化pool -> 启动Sweeper线程
但是启动Sweeper之前有一步判断
org.apache.tomcat.jdbc.pool.PoolProperties
@Override
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;
}
Sweeper线程执行任务:
@Override
public void run() {
ConnectionPool pool = this.pool.get();
if (pool == null) {
stopRunning();
} else if (!pool.isClosed() &&
(System.currentTimeMillis() - lastRun) > sleepTime) {
lastRun = System.currentTimeMillis();
try {
if (pool.getPoolProperties().isRemoveAbandoned())
pool.checkAbandoned();
if (pool.getPoolProperties().getMinIdle() < pool.idle
.size())
pool.checkIdle();
if (pool.getPoolProperties().isTestWhileIdle())
pool.testAllIdle();
} catch (Exception x) {
log.error("", x);
}
}
}
在 checkAbandoned 这个方法中,就包含了超时的连接给干掉,这个超时是超过Abandoned time 这个设置的时间.
public void checkAbandoned() {
try {
if (busy.size()==0) return;
Iterator<PooledConnection> locked = busy.iterator();
int sto = getPoolProperties().getSuspectTimeout();
while (locked.hasNext()) {
PooledConnection con = locked.next();
boolean setToNull = false;
try {
con.lock();
//the con has been returned to the pool
//ignore it
if (idle.contains(con))
continue;
long time = con.getTimestamp();
long now = System.currentTimeMillis();
if (shouldAbandon() && (now - time) > con.getAbandonTimeout()) {
busy.remove(con);
abandon(con);
setToNull = true;
} else if (sto > 0 && (now - time) > (sto*1000)) {
suspect(con);
} else {
//do nothing
} //end if
} finally {
con.unlock();
if (setToNull)
con = null;
}
} //while
} catch (ConcurrentModificationException e) {
log.debug("checkAbandoned failed." ,e);
} catch (Exception e) {
log.warn("checkAbandoned failed, it will be retried.",e);
}
}
shouldAbandon()方法中 有需要设置这个参数的地方:abandonWhenPercentageFull
protected boolean shouldAbandon() {
if (poolProperties.getAbandonWhenPercentageFull()==0) return true;
float used = busy.size();
float max = poolProperties.getMaxActive();
float perc = poolProperties.getAbandonWhenPercentageFull();
return (used/max*100f)>=perc;
}
最后清除
/**
* thread safe way to abandon a connection
* signals a connection to be abandoned.
* this will disconnect the connection, and log the stack trace if logAbanded=true
* @param con PooledConnection
*/
protected void abandon(PooledConnection con) {
if (con == null)
return;
try {
con.lock();
String trace = con.getStackTrace();
if (getPoolProperties().isLogAbandoned()) {
log.warn("Connection has been abandoned " + con + ":" + trace);
}
if (jmxPool!=null) {
jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_ABANDON, trace);
}
//release the connection
release(con);
} finally {
con.unlock();
}
}
busy 和 idle队列
所有的连接都是通过borrow方法获得的, 这个方法中, 首先从idle队列里查找可用的连接对象,如果没有就创建(这里不谈一些限制条件)
而创建是直接创建到 busy 队列中的.
在用完连接后,调用return方法,这个时候,会close掉原有连接,如果等待的链接请求>0,则会生成一个连接对象, 放到idle队列中.
下面这个是return 方法调用的release方法
/**
* thread safe way to release a connection
* @param con PooledConnection
*/
protected void release(PooledConnection con) {
if (con == null)
return;
try {
con.lock();
if (con.release()) {
//counter only decremented once
size.addAndGet(-1);
con.setHandler(null);
}
} finally {
con.unlock();
}
// we've asynchronously reduced the number of connections
// we could have threads stuck in idle.poll(timeout) that will never be
// notified
if (waitcount.get() > 0) {
idle.offer(create(true));
}
}