线程池怎么关闭,你知道线程池是如何退出程序的吗?

 2023-09-22 阅读 30 评论 0

摘要:摘要:本文,我们就来从源码角度深度解析线程池是如何优雅的退出程序的。 本文分享自华为云社区《【高并发】从源码角度深度解析线程池是如何实现优雅退出的》,作者:冰 河 。 本文,我们就来从源码角度深度解析线程池是如何优雅的退出程序的。
摘要:本文,我们就来从源码角度深度解析线程池是如何优雅的退出程序的。

本文分享自华为云社区《【高并发】从源码角度深度解析线程池是如何实现优雅退出的》,作者:冰 河 。

本文,我们就来从源码角度深度解析线程池是如何优雅的退出程序的。首先,我们来看下ThreadPoolExecutor类中的shutdown()方法。

shutdown()方法

当使用线程池的时候,调用了shutdown()方法后,线程池就不会再接受新的执行任务了。但是在调用shutdown()方法之前放入任务队列中的任务还是要执行的。此方法是非阻塞方法,调用后会立即返回,并不会等待任务队列中的任务全部执行完毕后再返回。我们看下shutdown()方法的源代码,如下所示。

public void shutdown() {//获取线程池的全局锁final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {//检查是否有关闭线程池的权限checkShutdownAccess();//将当前线程池的状态设置为SHUTDOWNadvanceRunState(SHUTDOWN);//中断Worker线程interruptIdleWorkers();//为ScheduledThreadPoolExecutor调用钩子函数onShutdown(); // hook for } finally {//释放线程池的全局锁mainLock.unlock();}//尝试将状态变为TERMINATEDtryTerminate();
}

总体来说,shutdown()方法的代码比较简单,首先检查了是否有权限来关闭线程池,如果有权限,则再次检测是否有中断工作线程的权限,如果没有权限,则会抛出SecurityException异常,代码如下所示。

//检查是否有关闭线程池的权限
checkShutdownAccess();
//将当前线程池的状态设置为SHUTDOWN
advanceRunState(SHUTDOWN);
//中断Worker线程
interruptIdleWorkers();

其中,checkShutdownAccess()方法的实现代码如下所示。

private void checkShutdownAccess() {SecurityManager security = System.getSecurityManager();if (security != null) {security.checkPermission(shutdownPerm);final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {for (Worker w : workers)security.checkAccess(w.thread);} finally {mainLock.unlock();}}
}

线程池怎么关闭。对于checkShutdownAccess()方法的代码理解起来比较简单,就是检测是否具有关闭线程池的权限,期间使用了线程池的全局锁。

接下来,我们看advanceRunState(int)方法的源代码,如下所示。

private void advanceRunState(int targetState) {for (;;) {int c = ctl.get();if (runStateAtLeast(c, targetState) ||ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))break;}
}

advanceRunState(int)方法的整体逻辑就是:判断当前线程池的状态是否为指定的状态,在shutdown()方法中传递的状态是SHUTDOWN,如果是SHUTDOWN,则直接返回;如果不是SHUTDOWN,则将当前线程池的状态设置为SHUTDOWN。

接下来,我们看看showdown()方法调用的interruptIdleWorkers()方法,如下所示。

private void interruptIdleWorkers() {interruptIdleWorkers(false);
}

可以看到,interruptIdleWorkers()方法调用的是interruptIdleWorkers(boolean)方法,继续看interruptIdleWorkers(boolean)方法的源代码,如下所示。

private void interruptIdleWorkers(boolean onlyOne) {final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {for (Worker w : workers) {Thread t = w.thread;if (!t.isInterrupted() && w.tryLock()) {try {t.interrupt();} catch (SecurityException ignore) {} finally {w.unlock();}}if (onlyOne)break;}} finally {mainLock.unlock();}
}

上述代码的总体逻辑为:获取线程池的全局锁,循环所有的工作线程,检测线程是否被中断,如果没有被中断,并且Worker线程获得了锁,则执行线程的中断方法,并释放线程获取到的锁。此时如果onlyOne参数为true,则退出循环。否则,循环所有的工作线程,执行相同的操作。最终,释放线程池的全局锁。

线程池启动?接下来,我们看下shutdownNow()方法。

shutdownNow()方法

如果调用了线程池的shutdownNow()方法,则线程池不会再接受新的执行任务,也会将任务队列中存在的任务丢弃,正在执行的Worker线程也会被立即中断,同时,方法会立刻返回,此方法存在一个返回值,也就是当前任务队列中被丢弃的任务列表。

shutdownNow()方法的源代码如下所示。

public List<Runnable> shutdownNow() {List<Runnable> tasks;final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {//检查是否有关闭权限checkShutdownAccess();//设置线程池的状态为STOPadvanceRunState(STOP);//中断所有的Worker线程interruptWorkers();//将任务队列中的任务移动到tasks集合中tasks = drainQueue();} finally {mainLock.unlock();}/尝试将状态变为TERMINATEDtryTerminate();//返回tasks集合return tasks;
}

shutdownNow()方法的源代码的总体逻辑与shutdown()方法基本相同,只是shutdownNow()方法将线程池的状态设置为STOP,中断所有的Worker线程,并且将任务队列中的所有任务移动到tasks集合中并返回。

可以看到,shutdownNow()方法中断所有的线程时,调用了interruptWorkers()方法,接下来,我们就看下interruptWorkers()方法的源代码,如下所示。

private void interruptWorkers() {final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {for (Worker w : workers)w.interruptIfStarted();} finally {mainLock.unlock();}
}

interruptWorkers()方法的逻辑比较简单,就是获得线程池的全局锁,循环所有的工作线程,依次中断线程,最后释放线程池的全局锁。

线程结束,在interruptWorkers()方法的内部,实际上调用的是Worker类的interruptIfStarted()方法来中断线程,我们看下Worker类的interruptIfStarted()方法的源代码,如下所示。

void interruptIfStarted() {Thread t;if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {try {t.interrupt();} catch (SecurityException ignore) {}}
}

发现其本质上调用的还是Thread类的interrupt()方法来中断线程。

awaitTermination(long, TimeUnit)方法

当线程池调用了awaitTermination(long, TimeUnit)方法后,会阻塞调用者所在的线程,直到线程池的状态修改为TERMINATED才返回,或者达到了超时时间返回。接下来,我们看下awaitTermination(long, TimeUnit)方法的源代码,如下所示。

public boolean awaitTermination(long timeout, TimeUnit unit)throws InterruptedException {//获取距离超时时间剩余的时长long nanos = unit.toNanos(timeout);//获取Worker线程的的全局锁final ReentrantLock mainLock = this.mainLock;//加锁mainLock.lock();try {for (;;) {//当前线程池状态为TERMINATED状态,会返回trueif (runStateAtLeast(ctl.get(), TERMINATED))return true;//达到超时时间,已超时,则返回falseif (nanos <= 0)return false;//重置距离超时时间的剩余时长nanos = termination.awaitNanos(nanos);}} finally {//释放锁mainLock.unlock();}
}

上述代码的总体逻辑为:首先获取Worker线程的独占锁,后在循环判断当前线程池是否已经是TERMINATED状态,如果是则直接返回true,否则检测是否已经超时,如果已经超时,则返回false。

如果未超时,则重置距离超时时间的剩余时长。接下来,进入下一轮循环,再次检测当前线程池是否已经是TERMINATED状态,如果是则直接返回true,否则检测是否已经超时,如果已经超时,则返回false。

如果未超时,则重置距离超时时间的剩余时长。以此循环,直到线程池的状态变为TERMINATED或者已经超时。

强制退出程序快捷键?

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/3/84914.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息