关于线程池ExecutorService的shutdown()与shutdownNow()方法的区别

问题

这两天被一个问题折腾着:一个线程池,可能会有上万个任务要执行。问题是,一旦最先运行的线程执行完,整个线程池就结束了,哪怕队列里面还有很多任务还在等待着被执行。

有问题的代码

    public static void main(String[] args){

        List<String> datas = new ArrayList<>();
        for (int i = 0; i < 15; i++){
            datas.add(String.valueOf(i));
        }

        BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
        ExecutorService es = new ThreadPoolExecutor(2, 4,
                0L, TimeUnit.MILLISECONDS, queue);

        List<String> result = new ArrayList<>();

       // Semaphore lock = new Semaphore(301);

        for (String s : datas ) {
            try {

               // lock.acquire();
                es.execute(() -> {
                    try {
                        //执行SQL: select sleep(1) num, name from user,  让该方法的调用暂停一下
                        TestThreadExecutor.getAll();
                        synchronized (result){
                            result.add(s);
                        }

                    } finally {
                        //lock.release();
                        System.out.println(">>>>>>" + s + "...queue>>>" + queue.size());
                    }
                });

                System.out.println("----------------->" + s + "...queue>>>" + queue.size());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        System.out.println("byebye~~~~~~~~~~~~~~");

        es.shutdownNow();
        try {
            System.out.println("wait......");
            es.awaitTermination(1, TimeUnit.DAYS);
        } catch (InterruptedException e) {

            e.printStackTrace();
        }

        System.out.println("datas size>>>" + datas.size() + "###result size>>>" + result.size() + "###queue size>>>" + queue.size());
    }

先贴出jdk8里 shutdownNow()shutdown() 方法的主要代码:

shutdownNow()

checkShutdownAccess();
advanceRunState(STOP);
interruptWorkers();
tasks = drainQueue();

shutdown()

checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor

注意: shutdownNow()方法的第四行drainQueue()方法会遍历线程池的队列workQueue,并将该队列中所有等待执行的任务全部remove掉。

drainQueue()方法的代码:

    private List<Runnable> drainQueue() {
        BlockingQueue<Runnable> q = workQueue;
        ArrayList<Runnable> taskList = new ArrayList<Runnable>();
        q.drainTo(taskList);
        if (!q.isEmpty()) {
            for (Runnable r : q.toArray(new Runnable[0])) {
                if (q.remove(r))
                    taskList.add(r);
            }
        }
        return taskList;
    }

总结

如果队列很大,不想执行完,只想让当前正在执行中的任务执行完就立马结束,可以调用shutdownNow()方法。如果想要队列中任务全部都执行完再结束,那么调用shutdown()方法。

后记

  1. 当时在网上copy了一段代码,代码里面是shutdownNow()方法,导致每次在刚执行完第一个任务时,整个线程池就结束了。因为这个原因折腾了两天,最后还是自己通过阅读JDK的代码才找到原因。

  2. 平时在用线程池的时候,直接用newFixedThreadPool、newCachedThreadPool或newSingleThreadExecutor就可以了,ThreadPoolExecutor偏底层了。

  3. 在查找问题的过程中,却搞明白了Semaphore的用法。用起来简单,用来做限流也很方便。

转载于:https://my.oschina.net/yangliu9420/blog/2988644

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值