Druid-代码段-4-3

所属文章:池化技术(一)Druid是如何管理数据库连接的?

本代码段对应流程4.2,防止内存泄漏的连接关闭检测:


//回收长期未归还的连接(再次说明:该方法仅在removeAbandoned设置为true的情况下触发)
    public int removeAbandoned() {
        int removeCount = 0;

        long currrentNanos = System.nanoTime();

        //这个列表用于存放满足条件的真正需要强制回收的连接
        List abandonedList = new ArrayList();

        activeConnectionLock.lock();
        try {
            //在removeAbandoned设置为true的情况下,所有被借出去的连接,都会被保存进activeConnections(参考主流程1),所以要进行“长期未归还”的检查,就是从activeConnections开始的
            Iterator iter = activeConnections.keySet().iterator();

            for (; iter.hasNext();) {
                DruidPooledConnection pooledConnection = iter.next();

                if (pooledConnection.isRunning()) {
                    continue; //如果当前连接正在使用中(指的是正在execute),则不处理
                }

                //利用当前时间和连接被借出去时的时间,计算出连接被借出去的时间有多久
                long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (1000 * 1000);

                if (timeMillis >= removeAbandonedTimeoutMillis) { //如果连接被借出去的时间超过removeAbandonedTimeoutMillis这个阈值,将会命中“主动归还”的逻辑检查
                    iter.remove(); //先从activeConnections移除
                    pooledConnection.setTraceEnable(false); //标记为false,防止回收时重复removeactiveConnections,可以参考主流程5
                    abandonedList.add(pooledConnection); //放入“强制回收”队列
                }
            }
        } finally {
            activeConnectionLock.unlock();
        }

        if (abandonedList.size() > 0) { //如果“强制回收”队列大于0,说明有需要回收的连接
            for (DruidPooledConnection pooledConnection : abandonedList) { //循环这些连接
                final ReentrantLock lock = pooledConnection.lock;
                lock.lock(); //拿到连接的锁
                try {
                    if (pooledConnection.isDisable()) {
                        continue; //已经被回收的,则不管
                    }
                } finally {
                    lock.unlock();
                }

                //触发回收连接对象(pooledConnection)里的holcder(注意这里其实是把pooledConnection对象里的holder给回收至连接池了,pooledConnection对象本身会被销毁)
                JdbcUtils.close(pooledConnection); //这里触发的close,是DruidPooledConnection的close,也就是会触发recycle方法的close
                pooledConnection.abandond(); //标记为
                removeAbandonedCount++;
                removeCount++;

                if (isLogAbandoned()) { //日志打印,忽略
                    StringBuilder buf = new StringBuilder();
                    buf.append("abandon connection, owner thread: ");
                    buf.append(pooledConnection.getOwnerThread().getName());
                    buf.append(", connected at : ");
                    buf.append(pooledConnection.getConnectedTimeMillis());
                    buf.append(", open stackTrace\n");

                    StackTraceElement[] trace = pooledConnection.getConnectStackTrace();
                    for (int i = 0; i < trace.length; i++) {
                        buf.append("\tat ");
                        buf.append(trace[i].toString());
                        buf.append("\n");
                    }

                    buf.append("ownerThread current state is " + pooledConnection.getOwnerThread().getState()
                            + ", current stackTrace\n");
                    trace = pooledConnection.getOwnerThread().getStackTrace();
                    for (int i = 0; i < trace.length; i++) {
                        buf.append("\tat ");
                        buf.append(trace[i].toString());
                        buf.append("\n");
                    }

                    LOG.error(buf.toString());
                }
            }
        }

        return removeCount; //返回本次被强制回收的连接个数
    }
posted @ 2019-09-21 21:04  是胖虎捏  阅读(258)  评论(0编辑  收藏  举报