一般情况下,当我们频繁的使用线程的时候,为了节约资源快速响应需求,我们都会考虑使用线程池,线程池使用完毕都会想着关闭,关闭的时候一般情况下会用到shutdown和shutdownNow,这两个函数都能够用来关闭线程池,那么他们俩之间的区别是什么呢?下面我就用一句话来说明白shutdown和shutdownNow的区别。
一、shutdown 和 shutdownNow 区别
shutdown只是将线程池的状态设置为SHUTWDOWN状态,正在执行的任务会继续执行下去,没有被执行的则中断。而shutdownNow则是将线程池的状态设置为STOP,正在执行的任务则被停止,没被执行任务的则返回。
举个工人吃包子的例子,一个厂的工人(Workers)正在吃包子(可以理解为任务),假如接到shutdown的命令,那么这个厂的工人们则会把手头上的包子给吃完,没有拿到手里的笼子里面的包子则不能吃!而如果接到shutdownNow的命令以后呢,这些工人们立刻停止吃包子,会把手头上没吃完的包子放下,更别提笼子里的包子了。
二、线程状态知识延伸
在ThreadPoolExecutor中定义了关于线程状态的几个变量如下:
// runState is stored in the high-order bitsprivatestaticfinalintRUNNING=-1<<COUNT_BITS; privatestaticfinalintSHUTDOWN=0<<COUNT_BITS; privatestaticfinalintSTOP=1<<COUNT_BITS; privatestaticfinalintTIDYING=2<<COUNT_BITS; privatestaticfinalintTERMINATED=3<<COUNT_BITS;
1、当创建线程池后,初始时,线程池处于RUNNING状态,此时线程池中的任务为0;
2、如果调用了shutdown()方法,则线程池处于SHUTDOWN状态,此时线程池不能够接受新的任务,它会等待所有任务执行完毕;
3、如果调用了shutdownNow()方法,则线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务;
4、当所有的任务已终止,ctl 记录的”任务数量”为0,线程池会变为TIDYING状态。接着会执行terminated()函数;
5、线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED,线程池被设置为TERMINATED状态。
三、源码分析两者主要的区别
shutdown 源码
publicvoidshutdown() { finalReentrantLockmainLock=this.mainLock; mainLock.lock(); try { checkShutdownAccess(); // 高亮advanceRunState(SHUTDOWN); interruptIdleWorkers(); onShutdown(); } finally { mainLock.unlock(); } tryTerminate(); }
shutdownNow 源码
publicList<Runnable>shutdownNow() { List<Runnable>tasks; finalReentrantLockmainLock=this.mainLock; mainLock.lock(); try { checkShutdownAccess(); // 高亮advanceRunState(STOP); interruptWorkers(); // 高亮tasks=drainQueue(); } finally { mainLock.unlock(); } tryTerminate(); // 高亮returntasks; }
Ps:从源码【高亮】注释可以很清晰的看出两者的区别,shutdown使用了以后会置状态为SHUTDOWN,而shutdownNow为STOP。此外,shutdownNow会返回任务列表。