面试官:说说停止线程池的执行流程?

对于我们使用的线程池 ThreadPoolExecutor 来说,停止线程池的方法有以下两个:

  1. shutdown():优雅的关闭线程池,即不再接受新任务,但会等待已提交任务(包括正在执行的任务和在队列中等待的任务)执行完毕。等待所有任务都执行完毕后,线程池才会进入终止状态
  2. shutdownNow():尝试停止所有正在执行的任务,并返回等待执行的任务列表。正在执行的任务可能会被中断,适用于需要立即停止线程池,但不关心正在执行的任务是否立即完成的情况下。

1.代码演示

下面通过代码案例,咱们来了解一下 shutdown() 和 shutdownNow() 方法的具体使用。

1.1 shutdown() 方法执行

我们将线程池核心和最大线程数都设置为 2,任务队列可以存储 10 个任务,一次性添加了 5 个任务,每个任务执行 2s 以上,添加完任务之后执行停止方法,并在 1s 之后尝试添加另一个新任务,如下代码所示:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolExecutorShutdownTest {
    public static void main(String[] args) {
        // 创建线程
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2,
                2,
                1000,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(10),
                new RejectedExecutionHandler() {
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                        System.out.println("执行拒绝策略");
                    }
                });
        // 添加任务
        for (int i = 0; i < 5; i++) {
            executor.submit(() -> {
                String tName = Thread.currentThread().getName();
                System.out.println(tName + ":开始执行任务!");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(tName + ":结束执行任务!");
            });
        }
        // 停止线程
        executor.shutdown();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 添加新任务
        executor.submit(() -> System.out.println("最后一个新任务"));
    }
}

以上程序的执行结果如下:

alt

从以上结果可以看出,执行 shutdown() 方法后,程序会等待线程池中的所有任务全部执行完在关闭,再次期间线程池会拒绝加入新任务,并调用线程池的拒绝策略

1.2 shutdownNow()方法执行

如果将 shutdown() 方法换成 shutdownNow() 方法后,以上程序的执行结果如下:

alt

也就是说,调用 shutdownNow() 之后,正在执行的任务会被立即停止,且任务队列中未执行的任务也会被清除,调用 shutdownNow() 方法后新加入的任务会被拒绝,并执行线程池的拒绝策略

2.shutdown()执行流程

shutdown() 方法执行源码如下:

public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        advanceRunState(SHUTDOWN);
        interruptIdleWorkers();
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
}

该源码执行流程如下:

  1. 加锁:在多线程环境下,关闭操作涉及到修改关键状态和执行一些可能影响多个线程的操作。使用锁可以确保这些操作的原子性和一致性,避免多个线程同时进行关闭操作导致数据不一致或出现意外情况
  2. 检查关闭权限:在关闭之前进行状态检查可以确保关闭操作是合法的,避免在不适当的时候进行关闭。推进状态可以让其他代码部分能够根据当前执行器的状态做出正确的反应。
  3. 将状态设置为 SHUTDOWN:阻止新任务提交但完成现有任务。
  4. 中断空闲线程
  5. 调用 onShutdown 方法(钩子方法):可能用于在关闭时执行一些特定的清理或自定义操作,比如释放资源等。
  6. 释放锁
  7. 尝试终止线程池:如果所有任务已完成的情况下,会真正的终止线程池。

shutdown() 方法的执行流程如下图所示:

alt

课后思考

为什么需要关闭线程池?关闭线程池的场景有哪些?说说 shutdownNow() 的执行流程?

#java##八股#
全部评论

相关推荐

不愿透露姓名的神秘牛友
10-10 20:26
已编辑
点赞 评论 收藏
分享
头像
09-22 23:08
重庆大学 Java
今天city&nbsp;cycle回来的路上遇到了我大二下学期的英语老师Mr.Josh上他的课很有意思,我喜欢上去分享一些中国特色文化。记得有一次跟Josh介绍我的专业,我说在中国程序员35岁就会失业的时候他很诧异。有一节课他以电车难题为例子,让我们举一个类似的。我举的是鲁迅的黑房间There&nbsp;is&nbsp;a&nbsp;black&nbsp;house,&nbsp;some&nbsp;people&nbsp;sleep&nbsp;in&nbsp;there.&nbsp;One&nbsp;day&nbsp;you&nbsp;wake&nbsp;up,&nbsp;and&nbsp;find&nbsp;that&nbsp;the&nbsp;black&nbsp;house&nbsp;is&nbsp;killing&nbsp;you&nbsp;guys&nbsp;slowly.&nbsp;You&nbsp;can&nbsp;wake&nbsp;others&nbsp;up&nbsp;to&nbsp;dig&nbsp;a&nbsp;hole&nbsp;to&nbsp;run&nbsp;away,&nbsp;but&nbsp;it&nbsp;may&nbsp;be.&nbsp;May&nbsp;be&nbsp;you&nbsp;can't&nbsp;make&nbsp;it,&nbsp;and&nbsp;you&nbsp;with&nbsp;your&nbsp;friend&nbsp;will&nbsp;suffer&nbsp;because&nbsp;they&nbsp;wake&nbsp;up&nbsp;from&nbsp;a&nbsp;wonderful&nbsp;dream&nbsp;and&nbsp;find&nbsp;out&nbsp;everything&nbsp;is&nbsp;fake&nbsp;and&nbsp;can&nbsp;do&nbsp;nothing.&nbsp;So,&nbsp;would&nbsp;you&nbsp;wake&nbsp;them&nbsp;up&nbsp;try&nbsp;to&nbsp;dig&nbsp;a&nbsp;hole,&nbsp;or&nbsp;just&nbsp;let&nbsp;them&nbsp;sleep&nbsp;我和另外一个同学认为是不要叫醒他们,原因是叫醒他们之后,他们反而会觉得你破坏了他们的美梦,他们并不会把你当作hero,相反会把你当作异端烧死。在之后我没上过那么有意思的课了,不得不说,我本科期间所有的快乐时光都在大二下学期。那段时间就算被吊翘嘴也很快乐。我有大把的时间去浪费,我有大把的机会去尝试,我有大把的未来去幻想。大二的时候学长告诉我要去学Java,方能在如今恶劣的就业环境获得一线生机。我被从美梦中叫醒,之后我便陷入了漫长的dig&nbsp;a&nbsp;hole中了
牛客956583862号:唉,都是Java毁了我
点赞 评论 收藏
分享
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务