java8 ThreadPoolExecutor之shutdown()与shutdownNow()的相同与不同

研究ThreadPoolExecutor源码时,发现两个方法:shutdown()和shutdownNow(),从名字上看都是关闭,只是后者多了一个Now,那么它们两个有什么区别呢?
首先先来看代码:

    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(SHUTDOWN);//通过自旋锁不断的修改线程池状态,直到修改成功为止
            interruptIdleWorkers();
            onShutdown(); // 空实现,子类可以覆盖
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
    }
    public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(STOP);//通过自旋锁不断的修改线程池状态,直到修改成功为止
            interruptWorkers();
            tasks = drainQueue();
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        return tasks;
    }

先来说共同点:

  1. 都是public的;
  2. 调用这两个方法之后,调用execute()方法添加新任务都会被拒绝;
  3. 都会对线程发出中断;
  4. 执行线程中断和修改状态前,都会加锁;
  5. 如果阻塞队列中没有任务而且没有运行的线程,两个方法都会将线程池状态修改为TERMINATED,这个操作是在tryTerminate()中完成的;
  6. 调用这两个方法都会对正在运行的线程发出中断,但是不会强行销毁线程,因此尽管执行了这两个方法,线程池可能还会运行一段时间。

下面来看一下两者的不同点

  1. 修改线程池的状态不同,shutdown()将状态修改为SHUTDOWN,shutdownNow()将状态修改为STOP,修改状态时,调用的方法都是相同的:
	//入参是目标状态
    private void advanceRunState(int targetState) {
        for (;;) {
            int c = ctl.get();
            if (runStateAtLeast(c, targetState) ||
                ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
                break;
        }
    }
  1. shutdown()对空闲线程发起中断,而shutdownNow()对所有的线程发起中断;
  2. shutdownNow()调用drainQueue()将阻塞队列清空,并且将阻塞队列中的任务返回给调用方,下面是drainQueue()的代码;
    private List<Runnable> drainQueue() {
        BlockingQueue<Runnable> q = workQueue;
        //新建List对象,用于存储阻塞队列中的任务
        ArrayList<Runnable> taskList = new ArrayList<Runnable>();
        q.drainTo(taskList);//清空阻塞队列,将任务放到新建的List中
        if (!q.isEmpty()) {
            for (Runnable r : q.toArray(new Runnable[0])) {
                if (q.remove(r))
                    taskList.add(r);
            }
        }
        return taskList;
    }
  1. 两个方法的最后都调用了tryTerminate(),因为shutdown()不会清空阻塞队列,所以两个方法执行tryTerminate()还有些区别,如果阻塞队列中还有任务,或者还有正在运行的线程,都会造成shutdown()返回,而shutdownNow()只关心是否还有运行的线程,如果有,选择一个线程发起中断便返回了。
    final void tryTerminate() {
        for (;;) {
            int c = ctl.get();
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return;
            if (workerCountOf(c) != 0) { 
                interruptIdleWorkers(ONLY_ONE);
                return;
            }
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        terminated();
                    } finally {
                        ctl.set(ctlOf(TERMINATED, 0));
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值