通过一个例子理解线程池优雅关闭的过程
@ToString
public class Task implements Runnable {
int index;
public Task(int index) {
this.index = index;
}
@Override
public void run() {
System.out.println("开始执行 " + index);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
System.out.println("任务被中断 " + index);
return;
}
System.out.println("执行完成 " + index);
}
}
public class ShutdownDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
for (int i = 0; i < 10; i++) {
System.out.println("进入循环 " + i);
if (i == 5) {
executorService.shutdown();
}
try {
executorService.execute(new Task(i));
} catch (RejectedExecutionException e) {
System.out.println("线程池关闭,拒绝执行 " + i);
}
}
try {
System.out.println("main 等待线程池关闭");
boolean isStop = executorService.awaitTermination(2, TimeUnit.SECONDS);
System.out.println("main 第一次等待线程池关闭结果 " + isStop);
if (!isStop) {
System.out.println("main 尝试停止正在执行的任务");
List<Runnable> runnables = executorService.shutdownNow();
System.out.println("main 等待中的任务已全部移除 " + runnables);
isStop = executorService.awaitTermination(2, TimeUnit.SECONDS);
System.out.println("main 第二次等待线程池关闭结果 " + isStop);
if (!isStop) {
System.out.println("线程池终止失败");
}
}
} catch (InterruptedException e) {
System.out.println("main err " + e.getMessage());
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
简单说一下代码:
- 创建了2个线程的线程池
- 尝试用这个线程池执行10次任务(Task)
- 在循环i=5时,关闭线程池,所以i从5到9都会被拒绝执行,执行中和等待中的任务为0-4
- main线程中等待2s,因为每个任务要休眠2s,并且线程池只有2个线程,此时应该有任务在等待队列中
- main线程中尝试中断线程池中正在执行的任务,并且返回等待中的任务
- main线程再次等待2s,再确认线程池是否关闭成功
执行代码,输出如下
进入循环 0
进入循环 1
进入循环 2
进入循环 3
进入循环 4
进入循环 5
开始执行 0
开始执行 1
线程池关闭,拒绝执行 5
进入循环 6
线程池关闭,拒绝执行 6
进入循环 7
线程池关闭,拒绝执行 7
进入循环 8
线程池关闭,拒绝执行 8
进入循环 9
线程池关闭,拒绝执行 9
main 等待线程池关闭
执行完成 1
执行完成 0
开始执行 2
开始执行 3
main 第一次等待线程池关闭结果 false
main 尝试停止正在执行的任务
任务被中断 2
任务被中断 3
main 等待中的任务已全部移除 [Task(index=4)]
main 第二次等待线程池关闭结果 true
参考
jdk17 docs