第九章、销毁线程的 shrink 方法

本文深入探讨Java编程中线程销毁的重要方法——shrink。内容聚焦于如何在初始化过程中启动销毁线程,并分析其在排序算法和多线程开发中的应用。

在init方法中会启动销毁线程
com.alibaba.druid.pool.DruidDataSource#createAndStartDestroyThread

	protected void createAndStartDestroyThread() {
        destroyTask = new DestroyTask();

        if (destroyScheduler != null) {
            long period = timeBetweenEvictionRunsMillis;
            if (period <= 0) {
                period = 1000;
            }
            destroySchedulerFuture = destroyScheduler.scheduleAtFixedRate(destroyTask, period, period,
                    TimeUnit.MILLISECONDS);
            initedLatch.countDown();
            return;
        }

        String threadName = "Druid-ConnectionPool-Destroy-" + System.identityHashCode(this);
        destroyConnectionThread = new DestroyConnectionThread(threadName);
        destroyConnectionThread.start();
    }

com.alibaba.druid.pool.DruidDataSource.DestroyConnectionThread

	public class DestroyConnectionThread extends Thread {

        public DestroyConnectionThread(String name) {
            super(name);
            this.setDaemon(true);
        }

        public void run() {
            initedLatch.countDown();

            for (; ; ) {
                // 从前面开始删除
                try {

                    if (closed || closing) {
                        break;
                    }

                    if (timeBetweenEvictionRunsMillis > 0) {
                        Thread.sleep(timeBetweenEvictionRunsMillis);//60s
                    } else {
                        Thread.sleep(1000); //
                    }

                    if (Thread.interrupted()) {
                        break;
                    }

                    destroyTask.run();
                } catch (InterruptedException e) {
                    break;
                }
            }
        }

    }

com.alibaba.druid.pool.DruidDataSource.DestroyTask

	public class DestroyTask implements Runnable {
        public DestroyTask() {

        }

        @Override
        public void run() {
            shrink(true, keepAlive);

            if (isRemoveAbandoned()) {
                removeAbandoned();
            }
        }

    }

com.alibaba.druid.pool.DruidDataSource#shrink(boolean, boolean)


 public void shrink(boolean checkTime, boolean keepAlive) {
        try {
            lock.lockInterruptibly();
        } catch (InterruptedException e) {
            return;
        }

        boolean needFill = false;
        int evictCount = 0;
        int keepAliveCount = 0;
        int fatalErrorIncrement = fatalErrorCount - fatalErrorCountLastShrink;
        fatalErrorCountLastShrink = fatalErrorCount;

        try {
            if (!inited) {
                return;
            }
            // 池子里可用的资源数-最小空闲数 = 需要销毁的资源数
            final int checkCount = poolingCount - minIdle;
            final long currentTimeMillis = System.currentTimeMillis();
            for (int i = 0; i < poolingCount; ++i) {
                DruidConnectionHolder connection = connections[i];

                // 这几个参数不知道,满足条件后会把连接放进keepAliveConnections,然后下一个
                if ((onFatalError || fatalErrorIncrement > 0) && (lastFatalErrorTimeMillis > connection.connectTimeMillis)) {
                    keepAliveConnections[keepAliveCount++] = connection;
                    continue;
                }

                // 检查时间
                if (checkTime) {
                    // 如果设置了物理连接过期时间
                    if (phyTimeoutMillis > 0) {
                        long phyConnectTimeMillis = currentTimeMillis - connection.connectTimeMillis;
                        if (phyConnectTimeMillis > phyTimeoutMillis) {
                            // 连接使用时间大于阈值,将 holder 保存到 evictConnections 中
                            evictConnections[evictCount++] = connection;
                            continue;
                        }
                    }

                    // 当前时间-上次活跃时间 = 空闲时间
                    long idleMillis = currentTimeMillis - connection.lastActiveTimeMillis;

                    // 空闲时间小于最小可驱逐空闲时间并且小于保活时间,下面两个不用执行了,
                    // 我理解应该是 continue ????? 但是为什么停止循环????
                    // holder在connection中按照时间的排序的么?这样可以解释
                    if (idleMillis < minEvictableIdleTimeMillis
                            && idleMillis < keepAliveBetweenTimeMillis
                    ) {
                        break;
                    }

                    // 空闲时间大于最小可驱逐时间阈值
                    if (idleMillis >= minEvictableIdleTimeMillis) {
                        // 清除额度
                        if (checkTime && i < checkCount) {
                            evictConnections[evictCount++] = connection;
                            continue;
                            // 这种情况必须清除
                        } else if (idleMillis > maxEvictableIdleTimeMillis) {
                            evictConnections[evictCount++] = connection;
                            continue;
                        }
                    }
                    //空闲时间大于保活时间的,同样也要清除,因为过了保活的时间
                    if (keepAlive && idleMillis >= keepAliveBetweenTimeMillis) {
                        keepAliveConnections[keepAliveCount++] = connection;
                    }
                } else {
                    // 不需要检查参数,数出需要销毁的,直接放进 evictConnections
                    if (i < checkCount) {
                        evictConnections[evictCount++] = connection;
                    } else {
                        break;
                    }
                }
            }

            // 所有要清理的数量
            int removeCount = evictCount + keepAliveCount;
            if (removeCount > 0) {
                // 将后面的存活的holder直接前移覆盖移除的holder
                System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount);
                // 将后面的置为null
                Arrays.fill(connections, poolingCount - removeCount, poolingCount, null);
                // 可用资源减少
                poolingCount -= removeCount;
            }
            keepAliveCheckCount += keepAliveCount;

            // 包活 同时 池中资源 + 使用资源 < 最小空闲数
            if (keepAlive && poolingCount + activeCount < minIdle) {
                // 需要增加资源
                needFill = true;
            }
        } finally {
            lock.unlock();
        }
        // 需要销毁的
        if (evictCount > 0) {
            for (int i = 0; i < evictCount; ++i) {
                DruidConnectionHolder item = evictConnections[i];
                Connection connection = item.getConnection(); // ConnectionProxyImpl
                JdbcUtils.close(connection); // 关闭物理连接
                destroyCountUpdater.incrementAndGet(this);
            }
            Arrays.fill(evictConnections, null);
        }

        if (keepAliveCount > 0) {
            // keep order
            // 倒着来,时间从新到旧,抢救一下最新的
            for (int i = keepAliveCount - 1; i >= 0; --i) {
                DruidConnectionHolder holer = keepAliveConnections[i];
                Connection connection = holer.getConnection();
                holer.incrementKeepAliveCheckCount();

                boolean validate = false;
                try {
                    // 检查连接是有效
                    this.validateConnection(connection);
                    // 有效
                    validate = true;
                } catch (Throwable error) {
                    // 无效
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("keepAliveErr", error);
                    }
                    // skip
                }

                boolean discard = !validate;  // discard 放弃,无效的放弃
                if (validate) {
                    holer.lastKeepTimeMillis = System.currentTimeMillis();
                    // 向connections存放holder,如果放置成功,则返回true
                    // 如果connections中存在当前holder 或者池中资源大于最大活动数,返回false
                    boolean putOk = put(holer, 0L, true);
                    if (!putOk) {
                        // 为什么connections中存在keepLive中的holder,要把这个关闭??不理解
                        discard = true;
                    }
                }

                if (discard) {
                    try {
                        connection.close();
                    } catch (Exception e) {
                        // skip
                    }

                    lock.lock();
                    try {
                        discardCount++;

                        // 如果 活动数量 + 池中数量 < 最小空闲
                        if (activeCount + poolingCount <= minIdle) {
                            // 需要唤醒创建资源的线程
                            emptySignal();
                        }
                    } finally {
                        lock.unlock();
                    }
                }
            }
            this.getDataSourceStat().addKeepAliveCheckCount(keepAliveCount);
            Arrays.fill(keepAliveConnections, null);
        }

        if (needFill) {
            lock.lock();
            try {
                int fillCount = minIdle - (activeCount + poolingCount + createTaskCount);
                for (int i = 0; i < fillCount; ++i) {
                    // 需要唤醒创建资源的线程
                    emptySignal();
                }
            } finally {
                lock.unlock();
            }
        } else if (onFatalError || fatalErrorIncrement > 0) {
            lock.lock();
            try {
                emptySignal();
            } finally {
                lock.unlock();
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值