线程池(二)线程池关闭

137 阅读3分钟

线程池关闭

tryTerminate实现

tryTerminate()不会强制终止线程池,只是做一下检测,只有在workerCount为0,workQueue为空时,才会关闭线程池

final void tryTerminate() {
    for (;;) {
        int c = ctl.get();
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;
        if (workerCountOf(c) != 0) { // Eligible to terminate
            interruptIdleWorkers(ONLY_ONE);
            return;
        }
        
        // 1. 当workQueue为空(没有任务需要执行),且workCount为0(线程回收完)时,才会走到这里
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 2. 设置线程池状态为TIDYING
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {
                    terminated();
                } finally {
                    // 3. 设置线程池状态为TERMINATED
                    ctl.set(ctlOf(TERMINATED, 0));
                    // 4. 激活termination的await系列方法而被阻塞的所有线程
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }
        // else retry on failed CAS
    }
}

shutdown操作

调用shutdown方法后,线程池不再接受新的任务,但是工作队列中的任务还是可以执行(在getTask()方法中,当线程池为SHUTDOWN时,若任务队列不为空,仍然会从任务队列中获取任务),该方法会立刻返回,并不等待队列完成再返回。

public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 1. 权限检查
        checkShutdownAccess();
        // 2. 设置当前线程池为SHUTDOWN状态
        advanceRunState(SHUTDOWN);
        // 3. 设置中断标记
        interruptIdleWorkers();
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        mainLock.unlock();
    }
    // 4. 尝试将状态设置为TERMINATED
    tryTerminate();
}

shutdown()方法中使用全局锁,保证只有一个线程可以执行调用shutdown方法设置中断位,interruptIdleWorkers()中尝试获取Work线程内的锁,获取成功设置中断标记。线程在运行时,会加Work线程内的锁,因此正在运行的任务不会设置中断标记位,这里中断的是阻塞在getTask()方法中从队列中获取任务的线程,即空闲线程(等待任务的线程)。

private void interruptIdleWorkers() {
    interruptIdleWorkers(false);
}

private void interruptIdleWorkers(boolean onlyOne) {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        for (Worker w : workers) {
            Thread t = w.thread;
            if (!t.isInterrupted() && w.tryLock()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                } finally {
                    w.unlock();
                }
            }
            if (onlyOne)
                break;
        }
    } finally {
        mainLock.unlock();
    }
}

shutdownNow操作

调用shutdownNow方法,线程池不再接收新的任务,并且会丢弃工作队列里面的任务(在getTask()方法中,当线程池为STOP时,方法会直接返回null,不执行任务队列中的任务),正在执行的任务会被中断,该方法会直接返回,返回值是队列中被丢弃的任务。

public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        advanceRunState(STOP);
        // 中断所有线程
        interruptWorkers();
        // 将队列移动到tasks中
        tasks = drainQueue();
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
    return tasks;
}

// 中断所有线程
private void interruptWorkers() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        for (Worker w : workers)
            w.interruptIfStarted();
    } finally {
        mainLock.unlock();
    }
}

// 中断线程
void interruptIfStarted() {
    Thread t;
    if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
        try {
            t.interrupt();
        } catch (SecurityException ignore) {
        }
    }
}

awaitTermination操作

当调用awaitTermination()方法后,会先判断线程池是否为TERMINATED,若是则返回true表示线程池已关闭;否则超时等待,当等待结束后,线程池仍未关闭,则返回false表示线程池未关闭。

public boolean awaitTermination(long timeout, TimeUnit unit)
    throws InterruptedException {
    long nanos = unit.toNanos(timeout);
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        for (;;) {
            if (runStateAtLeast(ctl.get(), TERMINATED))
                return true;
            if (nanos <= 0)
                return false;
            // 1. tryTerminate()方法会在线程池关闭后激活该等待的线程
            nanos = termination.awaitNanos(nanos);
        }
    } finally {
        mainLock.unlock();
    }
}

优雅关闭线程池

executor.shutdown();
//executor.shutdownNow();
try{
    boolean isRunning;
    do {
        // 循环判断线程池是否已关闭
        isRunning = !executor.awaitTermination(1, TimeUnit.SECONDS);
    }while (isRunning);
}catch (InterruptedException e){
    //...
}