天天看点

ThreadPoolExecutor的shutDown和shutDownNow的区别

本篇内容转载自https://blog.csdn.net/wyc199273/article/details/65470372,自己感觉原作者代码不是很好,做了一些小修改。

先写结论:

shutdown不再接受新的任务,并且等待之前提交的任务都执行完再关闭,阻塞队列中的任务不会再执行。

shutdownNow直接关闭活跃状态的所有线程,并返回阻塞队列中的任务集合。

执行后线程都会被释放。

先看shutdown方法,代码如下

package com.czm.thread.testMain;

import java.util.List;
import java.util.Random;
import java.util.concurrent.*;

/**
 * 测试shutdown和shutdownNow
 * shutdown不再接受新的任务,并且等待之前提交的任务都执行完再关闭
 * shutdownNow直接关闭活跃状态的所有线程,并返回阻塞队列中的任务集合
 *
 * @author chengzheming
 * @date 2019/1/11 11:50
 */
public class ExecutorServiceShutDownTest {

    /**
     * cpu核数
     */
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    /**
     * 核心线程数大小
     */
    private static final int corePoolSize = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    /**
     * 线程池最大容纳线程数
     */
    private static final int maximumPoolSize = CPU_COUNT * 2 + 1;
    
    public static void main(String[] args) {

        class MyThread implements Runnable {

            @Override
            public void run() {
                try {
                    Random random = new Random();
                    //生成[1, 4)范围的随机整数
                    int time = random.nextInt(3) + 1;
                    //用于抛出异常
                    TimeUnit.SECONDS.sleep(time);
                    System.out.println(Thread.currentThread().getName() + " complete , time = " + time + "s");
                } catch (InterruptedException e) {
                    //异常打断
                    System.out.println(Thread.currentThread().getName() + " Interrupted!");
                }
            }
        }

        /**
         * 推荐的创建线程池的方式,自定义线程池参数。
         * 核心线程数,最大线程数,线程空闲存活时间(对核心线程无效),时间单位,任务阻塞队列,任务拒绝策略
         */
        ExecutorService executorService = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10), new ThreadPoolExecutor.DiscardOldestPolicy());
        //提交50个任务给线程池去处理
        for (int i = 0; i < 50; i++) {
            executorService.submit(new MyThread());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (i == 30) {
                executorService.shutdown();
                //返回阻塞队列中的任务集合
                //List<Runnable> list = executorService.shutdownNow();
                //System.out.println(list.size());
            }
        }
    }
}
           

我想测试在i等于30时,shutdown是否会打断活跃的进程并不接受新线程。运行结果如下(要等一段时间程序才会停止,因为循环等待了1秒)

pool-1-thread-1 complete , time = 2s
pool-1-thread-2 complete , time = 3s
pool-1-thread-4 complete , time = 1s
pool-1-thread-3 complete , time = 3s
pool-1-thread-2 complete , time = 2s
pool-1-thread-4 complete , time = 3s
pool-1-thread-1 complete , time = 2s
pool-1-thread-3 complete , time = 3s
pool-1-thread-2 complete , time = 3s
pool-1-thread-4 complete , time = 3s
pool-1-thread-1 complete , time = 2s
pool-1-thread-3 complete , time = 2s
pool-1-thread-2 complete , time = 3s
pool-1-thread-4 complete , time = 3s
pool-1-thread-1 complete , time = 2s
pool-1-thread-2 complete , time = 2s
pool-1-thread-3 complete , time = 3s
pool-1-thread-1 complete , time = 1s
pool-1-thread-4 complete , time = 3s
pool-1-thread-2 complete , time = 1s
pool-1-thread-3 complete , time = 2s
pool-1-thread-1 complete , time = 3s
pool-1-thread-2 complete , time = 1s
pool-1-thread-4 complete , time = 3s
pool-1-thread-3 complete , time = 2s
pool-1-thread-2 complete , time = 1s
pool-1-thread-1 complete , time = 2s
pool-1-thread-4 complete , time = 1s
pool-1-thread-3 complete , time = 1s
pool-1-thread-2 complete , time = 1s
pool-1-thread-1 complete , time = 3s

Process finished with exit code 0
           

可以看到结果有31个任务执行完成。因为每次循环都睡眠了一秒所以没有任务在阻塞队列,因此根据结果可以推断出shutdown方法会等待活跃线程执行完再释放线程,并且不会接受新的任务执行。

那如果把循环中的TimeUnit.SECONDS.sleep(1);去掉呢,运行结果如下

pool-1-thread-4 complete , time = 1s
pool-1-thread-5 complete , time = 1s
pool-1-thread-1 complete , time = 1s
pool-1-thread-6 complete , time = 1s
pool-1-thread-9 complete , time = 1s
pool-1-thread-3 complete , time = 2s
pool-1-thread-8 complete , time = 2s
pool-1-thread-17 complete , time = 2s
pool-1-thread-14 complete , time = 2s
pool-1-thread-7 complete , time = 2s
pool-1-thread-12 complete , time = 2s
pool-1-thread-1 complete , time = 1s
pool-1-thread-6 complete , time = 1s
pool-1-thread-16 complete , time = 3s
pool-1-thread-10 complete , time = 3s
pool-1-thread-2 complete , time = 3s
pool-1-thread-13 complete , time = 3s
pool-1-thread-15 complete , time = 3s
pool-1-thread-11 complete , time = 3s
pool-1-thread-4 complete , time = 2s
pool-1-thread-14 complete , time = 1s
pool-1-thread-8 complete , time = 1s
pool-1-thread-9 complete , time = 3s
pool-1-thread-5 complete , time = 3s
pool-1-thread-17 complete , time = 2s
pool-1-thread-7 complete , time = 3s
pool-1-thread-3 complete , time = 3s

Process finished with exit code 0
           

这个时候阻塞队列会有任务,运行完成的任务有27个,正好是最大线程数加阻塞队列线程数,同样没有线程被打断,说明shutdown不再接受新的任务,但会执行完之前提交的任务和阻塞队列中的任务再关闭。

下面看shutdownNow,将for循环代码修改为

for (int i = 0; i < 50; i++) {
            executorService.submit(new MyThread());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (i == 30) {
                //executorService.shutdown();
                //返回阻塞队列中的任务集合
                List<Runnable> list = executorService.shutdownNow();
                System.out.println(list.size());
            }
        }
           

运行结果如下

pool-1-thread-2 complete , time = 1s
pool-1-thread-1 complete , time = 3s
pool-1-thread-3 complete , time = 2s
pool-1-thread-4 complete , time = 2s
pool-1-thread-3 complete , time = 2s
pool-1-thread-2 complete , time = 2s
pool-1-thread-1 complete , time = 3s
pool-1-thread-3 complete , time = 1s
pool-1-thread-4 complete , time = 3s
pool-1-thread-2 complete , time = 2s
pool-1-thread-1 complete , time = 2s
pool-1-thread-1 complete , time = 1s
pool-1-thread-3 complete , time = 3s
pool-1-thread-2 complete , time = 3s
pool-1-thread-4 complete , time = 3s
pool-1-thread-3 complete , time = 1s
pool-1-thread-1 complete , time = 3s
pool-1-thread-2 complete , time = 2s
pool-1-thread-3 complete , time = 1s
pool-1-thread-4 complete , time = 2s
pool-1-thread-1 complete , time = 1s
pool-1-thread-1 complete , time = 2s
pool-1-thread-3 complete , time = 2s
pool-1-thread-4 complete , time = 2s
pool-1-thread-2 complete , time = 1s
pool-1-thread-1 complete , time = 1s
pool-1-thread-3 complete , time = 3s
pool-1-thread-2 complete , time = 2s
pool-1-thread-4 complete , time = 3s
pool-1-thread-1 complete , time = 1s
pool-1-thread-3 Interrupted!
0

Process finished with exit code 0
           

完成的任务加一条打断的线程正好31条,证明shutdownNow确实会打断活跃的线程,因为阻塞队列为空所以返回list.size()值为0。

同样将循环中TimeUnit.SECONDS.sleep(1);去掉,运行结果如下

pool-1-thread-12 Interrupted!
pool-1-thread-7 Interrupted!
pool-1-thread-1 Interrupted!
pool-1-thread-3 Interrupted!
pool-1-thread-8 Interrupted!
pool-1-thread-9 Interrupted!
pool-1-thread-5 Interrupted!
pool-1-thread-4 Interrupted!
pool-1-thread-14 Interrupted!
pool-1-thread-13 Interrupted!
pool-1-thread-2 Interrupted!
pool-1-thread-10 Interrupted!
pool-1-thread-11 Interrupted!
pool-1-thread-6 Interrupted!
10
pool-1-thread-15 Interrupted!
pool-1-thread-16 Interrupted!
pool-1-thread-17 Interrupted!

Process finished with exit code 0
           

有17条线程被打断了,和我设置的最大线程数一样,再次证明了shutdownNow会打断活跃线程。输出list.size()值为10,与我设置的阻塞队列长度相同,证明shutdownNow的返回值确实是阻塞线程集合。

原来结论写错了,现在改了,如果还有错误欢迎指正,就是误导了别人十分抱歉。

继续阅读