6 停止线程池的正确方法
shutdown:调用了shutdown()方法不一定会立即停止,这个方法仅仅是初始整个关闭过程。因为线程池中的线程有可能正在运行,并且队列中也有待处理的任务,不可能说停就停。所以每当调用该方法时,线程池会把正在执行的任务和队列中等待的任务都执行完毕再关闭,并且在此期间如果接收到新的任务会被拒绝。
/** * 演示关闭线程池 */public class ShutDown { public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(10); for (int i = 0; i < 1000; i++) { executorService.execute(new ShutDownTask()); } Thread.sleep(1500); executorService.shutdown(); //再次提交任务 executorService.execute(new ShutDownTask()); }}class ShutDownTask implements Runnable { @Override public void run() { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); }}
isShutdown:可以用于判断线程池是否被shutdown了
/** * 演示关闭线程池 */public class ShutDown { public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(10); for (int i = 0; i < 1000; i++) { executorService.execute(new ShutDownTask()); } Thread.sleep(1500); System.out.println(executorService.isShutdown()); executorService.shutdown(); System.out.println(executorService.isShutdown()); //再次提交任务// executorService.execute(new ShutDownTask()); }}class ShutDownTask implements Runnable { @Override public void run() { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); }}
isTerminated:可以判断线程是否被完全终止了
将循环的次数改为100次,并且在第一次调用isTerminated方法的地方休眠10s
awaitTermination:传入等待时间,等待时间达到时判断是否停止了,主要用于检测。
//在3s后判断线程池是否被终止,返回boolean值System.out.println(executorService.awaitTermination(3L, TimeUnit.SECONDS));
shutdownNow:调用了这个方法时,线程池会立即终止,并返回没有被处理完的任务。如果需要继续执行这里的任务可以再次让线程池执行这些返回的任务。
7 任务太多,怎么拒绝?
7.1 拒绝的时机
当Executor关闭时,新提交的任务会被拒绝。
以及Executor对最大线程数和工作队列容量使用有限边界并且已经饱和时。
7.2 拒绝策略
AbortPolicy(中断策略):直接抛出异常进行拒绝
DiscardPolicy(丢弃策略):不会得到通知,默默的抛弃掉任务
DiscardOldestPolicy(丢弃最老的):由于队列中存储了很多任务,这个策略会丢弃在队列中存在时间最久的任务。
CallerRunsPolicy:比如主线程给线程池提交任务,但是线程池已经满了,在这种策略下会让提交任务的线程去执行。
总结:第四种拒绝策略相对于前三种更加“机智”一些,可以避免前面三种策略产生的损失。在第四种策略下可以降低提交的速度,达到负反馈的效果。
8 使用钩子为线程池加点料(可用于日志记录)
/** * 演示每个任务执行的前后放钩子函数 */public class PauseableThreadPool extends ThreadPoolExecutor { private boolean isPaused; private final ReentrantLock lock = new ReentrantLock(); private Condition unPaused = lock.newCondition(); public PauseableThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } public PauseableThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); } public PauseableThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler); } public PauseableThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); } @Override protected void beforeExecute(Thread t, Runnable r) { super.beforeExecute(t, r); lock.lock(); try { while (isPaused) { unPaused.await(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } private void pause() { lock.lock(); try { isPaused = true; } finally { lock.unlock(); } } public void resume() { lock.lock(); try { isPaused = false; //唤醒全部 unPaused.signalAll(); } finally { lock.unlock(); } } public static void main(String[] args) throws InterruptedException { PauseableThreadPool pauseableThreadPool = new PauseableThreadPool(10, 20, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); Runnable runnable = new Runnable() { @Override public void run() { System.out.println("我被执行"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } }; for (int i = 0; i < 10000; i++) { pauseableThreadPool.execute(runnable); } Thread.sleep(1500); pauseableThreadPool.pause(); System.out.println("线程池被暂停了"); Thread.sleep(1500); pauseableThreadPool.resume(); System.out.println("线程池被恢复了"); }}