package com.zang.concurrent.collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.*; /** * * 線程池 * * 要使用帶有ThreadFactory參數的ThreadPoolExecutor構造方法哦,這樣你就可以方便的設置線程名字啦。 less... (Ctrl+F1) * Inspection info: * 創建線程或線程池時請指定有意義的線程名稱,方便出錯時回溯。創建線程池的時候請使用帶ThreadFactory的構造函數,並且提供自定義ThreadFactory實現或者使用第三方實現。 * * ThreadFactory namedThreadFactory = new ThreadFactoryBuilder() * .setNameFormat("demo-pool-%d").build(); * ExecutorService singleThreadPool = new ThreadPoolExecutor(1, 1, * 0L, TimeUnit.MILLISECONDS, * new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); * * singleThreadPool.execute(()-> System.out.println(Thread.currentThread().getName())); * singleThreadPool.shutdown(); * * * * public class TimerTaskThread extends Thread { * public TimerTaskThread(){ * super.setName("TimerTaskThread"); … * } * * * @author Zhang Qiang * @Date 2019/9/9 9:26 */ public class ThreadPool { /** * 線程池 * newSingleThreadExecutor(),它的特點在於工作線程數目被限制為 1,操作一個無界的工作隊列,所以它保證了所有任務的都是被順序執行,最多會有一個任務處於活動狀態,並且不允許使用者改動線程池實例,因此可以避免其改變線程數目。 * newCachedThreadPool(),它是一種用來處理大量短時間工作任務的線程池,具有幾個鮮明特點:它會試圖緩存線程並重用,當無緩存線程可用時,就會創建新的工作線程;如果線程閑置的時間超過 60 秒,則被終止並移出緩存;長時間閑置時,這種線程池,不會消耗什么資源。其內部使用 SynchronousQueue 作為工作隊列。 * newFixedThreadPool(int nThreads),重用指定數目(nThreads)的線程,其背后使用的是無界的工作隊列,任何時候最多有 nThreads 個工作線程是活動的。這意味着,如果任務數量超過了活動隊列數目,將在工作隊列中等待空閑線程出現;如果有工作線程退出,將會有新的工作線程被創建,以補足指定的數目 nThreads。 * newSingleThreadScheduledExecutor() 創建單線程池,返回 ScheduledExecutorService,可以進行定時或周期性的工作調度。 * newScheduledThreadPool(int corePoolSize)和newSingleThreadScheduledExecutor()類似,創建的是個 ScheduledExecutorService,可以進行定時或周期性的工作調度,區別在於單一工作線程還是多個工作線程。 * newWorkStealingPool(int parallelism),這是一個經常被人忽略的線程池,Java 8 才加入這個創建方法,其內部會構建ForkJoinPool,利用Work-Stealing算法,並行地處理任務,不保證處理順序。 * ThreadPoolExecutor是最原始的線程池創建,上面1-3創建方式都是對ThreadPoolExecutor的封裝。 * * 線程池狀態: * private static final int RUNNING = -1 << COUNT_BITS; * private static final int SHUTDOWN = 0 << COUNT_BITS; * private static final int STOP = 1 << COUNT_BITS; * private static final int TIDYING = 2 << COUNT_BITS; * private static final int TERMINATED = 3 << COUNT_BITS; * * RUNNING:這個沒什么好說的,這是最正常的狀態:接受新的任務,處理等待隊列中的任務; * SHUTDOWN:不接受新的任務提交,但是會繼續處理等待隊列中的任務; * STOP:不接受新的任務提交,不再處理等待隊列中的任務,中斷正在執行任務的線程; * TIDYING:所有的任務都銷毀了,workCount 為 0。線程池的狀態在轉換為 TIDYING 狀態時,會執行鈎子方法 terminated(); * TERMINATED:terminated() 方法結束后,線程池的狀態就會變成這個; * RUNNING 定義為 -1,SHUTDOWN 定義為 0,其他的都比 0 大,所以等於 0 的時候不能提交任務,大於 0 的話,連正在執行的任務也需要中斷。 * * 各個狀態的轉換過程有以下幾種: * * RUNNING -> SHUTDOWN:當調用了 shutdown() 后,會發生這個狀態轉換,這也是最重要的; * (RUNNING or SHUTDOWN) -> STOP:當調用 shutdownNow() 后,會發生這個狀態轉換,這下要清楚 shutDown() 和 shutDownNow() 的區別了; * SHUTDOWN -> TIDYING:當任務隊列和線程池都清空后,會由 SHUTDOWN 轉換為 TIDYING; * STOP -> TIDYING:當任務隊列清空后,發生這個轉換; * TIDYING -> TERMINATED:這個前面說了,當 terminated() 方法結束后; * * */ public static Map<String, ExecutorService> getPool(){ //使用Executors方式創建 ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); //java8 ExecutorService workStealingPool = Executors.newWorkStealingPool(); ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2); //執行延遲任務 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2); ScheduledExecutorService singleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor(); //原始創建方式 ThreadPoolExecutor tp = new ThreadPoolExecutor(10, 10, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); Map<String, ExecutorService> map = new HashMap<>(7); map.put("singleThreadExecutor", singleThreadExecutor); map.put("cachedThreadPool", cachedThreadPool); map.put("fixedThreadPool", fixedThreadPool); map.put("singleThreadScheduledExecutor", singleThreadScheduledExecutor); map.put("scheduledThreadPool", scheduledThreadPool); map.put("workStealingPool", workStealingPool); map.put("tp", tp); return map; } }