您好,欢迎访问一九零五行业门户网

Java线程池怎样优雅地实现关闭?

shutdown()方法当使用线程池的时候,调用了shutdown()方法后,线程池就不会再接受新的执行任务了。但是在调用shutdown()方法之前放入任务队列中的任务还是要执行的。此方法是非阻塞方法,调用后会立即返回,并不会等待任务队列中的任务全部执行完毕后再返回。我们看下shutdown()方法的源代码,如下所示。
public void shutdown() { //获取线程池的全局锁 final reentrantlock mainlock = this.mainlock; mainlock.lock(); try { //检查是否有关闭线程池的权限 checkshutdownaccess(); //将当前线程池的状态设置为shutdown advancerunstate(shutdown); //中断worker线程 interruptidleworkers(); //为scheduledthreadpoolexecutor调用钩子函数 onshutdown(); // hook for } finally { //释放线程池的全局锁 mainlock.unlock(); } //尝试将状态变为terminated tryterminate();}
总体来说,shutdown()方法的代码比较简单,首先检查了是否有权限来关闭线程池,如果有权限,则再次检测是否有中断工作线程的权限,如果没有权限,则会抛出securityexception异常,代码如下所示。
//检查是否有关闭线程池的权限checkshutdownaccess();//将当前线程池的状态设置为shutdownadvancerunstate(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(); //设置线程池的状态为stop advancerunstate(stop); //中断所有的worker线程 interruptworkers(); //将任务队列中的任务移动到tasks集合中 tasks = drainqueue(); } finally { mainlock.unlock(); } /尝试将状态变为terminated tryterminate(); //返回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状态,会返回true if (runstateatleast(ctl.get(), terminated)) return true; //达到超时时间,已超时,则返回false if (nanos <= 0) return false; //重置距离超时时间的剩余时长 nanos = termination.awaitnanos(nanos); } } finally { //释放锁 mainlock.unlock(); }}
上述代码的总体逻辑为:首先获取worker线程的独占锁,后在循环判断当前线程池是否已经是terminated状态,如果是则直接返回true,否则检测是否已经超时,如果已经超时,则返回false。如果未超时,则重置距离超时时间的剩余时长。接下来,进入下一轮循环,再次检测当前线程池是否已经是terminated状态,如果是则直接返回true,否则检测是否已经超时,如果已经超时,则返回false。如果未超时,则重置距离超时时间的剩余时长。以此循环,直到线程池的状态变为terminated或者已经超时。
以上就是java线程池怎样优雅地实现关闭?的详细内容。
其它类似信息

推荐信息