public static void gracefulShutdown(Executor executor, int timeout) { if (!(executor instanceof ExecutorService) || isShutdown(executor)) { return; } final ExecutorService es = (ExecutorService) executor; try { es.shutdown(); // Disable new tasks from being submitted } catch (SecurityException ex2) { return; } catch (NullPointerException ex2) { return; } try { if (!es.awaitTermination(timeout, TimeUnit.MILLISECONDS)) { es.shutdownNow(); } } catch (InterruptedException ex) { es.shutdownNow(); Thread.currentThread().interrupt(); } if (!isShutdown(es)) { newThreadToCloseExecutor(es); } }
根据注释,shutdown方法只是用来停止接收新的task,但是不能保证老的task是否已经停止。如果抛出SecurityException,那么说明调用者是不能直接关闭这个线程池的。
如果要确保老的任务也停止的话,那么需要调用awaitTermination阻塞等待关闭的结果。
/** * Blocks until all tasks have completed execution after a shutdown * request, or the timeout occurs, or the current thread is * interrupted, whichever happens first. * * @param timeout the maximum time to wait * @param unit the time unit of the timeout argument * @return {@code true} if this executor terminated and * {@code false} if the timeout elapsed before termination * @throws InterruptedException if interrupted while waiting */ boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
如果返回结果是false,那么说明是超时返回,直接调用shutdownNow,这个方法尝试关闭你所有的线程,但是依然无法保证所有的线程都能够真正关闭,因为有些线程可能会忽略掉interrupt方法,如果需要知道最终的结果,跟shutdown方法一样,需要调用awaitTermination阻塞等待结果。
interrupt这个到底是啥?shutdownnow的时候也try了一下InterruptedException
如果一个线程处于running状态,对他调用interrupt,那么这个线程的状态继续运行,只是这个线程的标记位interrupted=true,也就是说无法通过中断方法终止一个线程,如果有业务需要,可以让线程在循环里面check这个状态位。
如果一个线程阻塞状态(wait方法阻塞、sleep方法阻塞),那么对这个线程调用interrupt方法,这个线程就会从阻塞状态返回过来,并且抛出InterruptedException异常,更重要的是interrupted=false,也就是说这种情况下不能依赖这个标志位了,如果业务上真有中断线程的需要的话,可以catch这个异常,增加一个新的标志位、check这个标志位作为是否结束线程的标志。
InterruptedException意味着阻塞状态的线程被interrupt了,为了不直接吞掉这个异常,把当前线程设置了标志位,供外面查询Thread.currentThread().interrupt()。
最后如果试了shutdown和shutdownnow都不行的话,那么生成了一个新的线程来关闭线程池,不能阻塞主线程太久。newThreadToCloseExecutor具体代码:
private static void newThreadToCloseExecutor(final ExecutorService es) { if (!isShutdown(es)) { shutdownExecutor.execute(new Runnable() { public void run() { try { for (int i = 0; i < 1000; i++) { es.shutdownNow(); if (es.awaitTermination(10, TimeUnit.MILLISECONDS)) { break; } } } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } catch (Throwable e) { logger.warn(e.getMessage(), e); } } }); } }
让一个新的线程多次轮训shutdownnow,然后await结果,如果await返回true,那么线程池全部终止。否则继续shutdownnow,吞掉着其中发生的InterruptedException异常。
原文地址:https://www.cnblogs.com/notlate/p/10204834.html