6 停止線程池的正確方法
shutdown:調用了shutdown()方法不一定會立即停止,這個方法僅僅是初始整個關閉過程。因為線程池中的線程有可能正在運行,並且隊列中也有待處理的任務,不可能說停就停。所以每當調用該方法時,線程池會把正在執行的任務和隊列中等待的任務都執行完畢再關閉,並且在此期間如果接收到新的任務會被拒絕。
<code>/** * 演示關閉線程池 */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()); }}/<code>
![Java線程池的個人總結(三)](http://p2.ttnews.xyz/loading.gif)
isShutdown:可以用於判斷線程池是否被shutdown了
<code>/** * 演示關閉線程池 */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()); }}/<code>
![Java線程池的個人總結(三)](http://p2.ttnews.xyz/loading.gif)
isTerminated:可以判斷線程是否被完全終止了
將循環的次數改為100次,並且在第一次調用isTerminated方法的地方休眠10s
awaitTermination:傳入等待時間,等待時間達到時判斷是否停止了,主要用於檢測。
<code>//在3s後判斷線程池是否被終止,返回boolean值System.out.println(executorService.awaitTermination(3L, TimeUnit.SECONDS));/<code>
shutdownNow:調用了這個方法時,線程池會立即終止,並返回沒有被處理完的任務。如果需要繼續執行這裡的任務可以再次讓線程池執行這些返回的任務。
7 任務太多,怎麼拒絕?
7.1 拒絕的時機
當Executor關閉時,新提交的任務會被拒絕。
以及Executor對最大線程數和工作隊列容量使用有限邊界並且已經飽和時。
7.2 拒絕策略
AbortPolicy(中斷策略):直接拋出異常進行拒絕
DiscardPolicy(丟棄策略):不會得到通知,默默的拋棄掉任務
DiscardOldestPolicy(丟棄最老的):由於隊列中存儲了很多任務,這個策略會丟棄在隊列中存在時間最久的任務。
CallerRunsPolicy:比如主線程給線程池提交任務,但是線程池已經滿了,在這種策略下會讓提交任務的線程去執行。
總結:第四種拒絕策略相對於前三種更加“機智”一些,可以避免前面三種策略產生的損失。在第四種策略下可以降低提交的速度,達到負反饋的效果。
8 使用鉤子為線程池加點料(可用於日誌記錄)
<code>/** * 演示每個任務執行的前後放鉤子函數 */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<runnable> workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } public PauseableThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<runnable> workQueue, ThreadFactory threadFactory) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); } public PauseableThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<runnable> workQueue, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler); } public PauseableThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<runnable> 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("線程池被恢復了"); }}/<runnable>/<runnable>/<runnable>/<runnable>/<code>
閱讀更多 青芽草 的文章