tomcat-jdbc关于回收连接对象的粗略分析

来源:互联网 发布:农村淘宝报名网站报名 编辑:程序博客网 时间:2024/05/16 08:23

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线程执行任务:

@Overridepublic 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));        }    }

                                             
0 0
原创粉丝点击