1. 程式人生 > >並發7-線程池

並發7-線程池

int 分開 queue tex single ret imu executor lock

用優雅的方式理解和使用線程池

  1. 線程池的目的
    (1)減少系統維護線程的開銷
    (2)解耦,運行和創建分開
    (3)線程可以復用

  2. 線程池的使用
    (1)接口Executor 提供方法execute(Runnable)執行線程命令
    (2)接口ExecutorService 提供方法shutdown() 啟動一次順序關閉,執行以前提交的任務,但不接受新任務
    技術分享圖片


    Future(框架):交給我一個任務,我給你一個發票,到時候用發票取結果。
    Executors

    此包中所定義的 ExecutorExecutorServiceScheduledExecutorService

    ThreadFactoryCallable 類的工廠和實用方法。此類支持以下各種方法:

    • 創建並返回設置有常用配置字符串的 ExecutorService 的方法。
    • 創建並返回設置有常用配置字符串的 ScheduledExecutorService 的方法。
    • 創建並返回“包裝的”ExecutorService 方法,它通過使特定於實現的方法不可訪問來禁用重新配置。
    • 創建並返回 ThreadFactory 的方法,它可將新創建的線程設置為已知的狀態。
    • 創建並返回非閉包形式的 Callable 的方法,這樣可將其用於需要 Callable 的執行方法中。

    (3)線程池的分類
    newFixedThreadPool(int nThreads)
    創建一個可重用固定線程數的線程池,以共享的無界隊列方式來運行這些線程。
    技術分享圖片


    newCachedThreadPool()
    創建一個可根據需要創建新線程的線程池,但是在以前構造的線程可用時將重用它們。(可變大小的線程池)
    技術分享圖片


    newSingleThreadExecutor()
    創建一個使用單個 worker 線程的 Executor,以無界隊列方式來運行該線程。
    技術分享圖片


    newScheduledThreadPool(int corePoolSize)
    創建一個線程池,它可安排在給定延遲後運行命令或者定期地執行。
    技術分享圖片



    (4)定義

    (5)使用

  3. 線程池的原理

    public static ExecutorService newCachedThreadPool() {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                          60L, TimeUnit.SECONDS,
                                          new SynchronousQueue<Runnable>());
        }
    

      

    public static ExecutorService newSingleThreadExecutor() {
            return new FinalizableDelegatedExecutorService
                (new ThreadPoolExecutor(1, 1,
                                        0L, TimeUnit.MILLISECONDS,
                                        new LinkedBlockingQueue<Runnable>()));
        }
    

      

    public static ExecutorService newFixedThreadPool(int nThreads) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>());
        }
    

      

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
            return new ScheduledThreadPoolExecutor(corePoolSize);
        }
    

      鏈接

    public ScheduledThreadPoolExecutor(int corePoolSize) {
            super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
                  new DelayedWorkQueue());
        }
    

      鏈接

    public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue) {
            this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                 Executors.defaultThreadFactory(), defaultHandler);
        }
    

      

    核心參數
    int corePoolSize 核心線程池的大小
    int maximumPoolSize 最大線程數量
    long keepAliveTime 線程保持活動的時間 為什麽這裏要有保持活動時間?因為存在核心線程池,與線程池同生命周期(同生共死),非核心也就是最大線程數量超過核心線程數量的線程,會存在生命周期。
    TimeUnit unit 線程保持活動的時間單位
    BlockingQueue<Runnable> workQueue 任務隊列(BlockingQueue:阻塞隊列)
    defaultHandler 拒絕策略

    線程池狀態:
    private static final int COUNT_BITS = Integer.SIZE - 3;  線程數量
    private static final int CAPACITY = (1 << COUNT_BITS) - 1; 最多容量
    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;

    狀態變化
    技術分享圖片
    Execute方法
    int c = ctl.get();//獲取當前線程池的狀態
            if (workerCountOf(c) < corePoolSize) {//當前線程數量小於 coreSize 時創建一個新的線程運行
                if (addWorker(command, true))
                    return;
                c = ctl.get();
            }
            if (isRunning(c) && workQueue.offer(command)) {//如果當前線程處於運行狀態,並且寫入阻塞隊列成功
                int recheck = ctl.get();
                if (! isRunning(recheck) && remove(command))  //雙重檢查,再次獲取線程狀態;如果線程狀態變了(非運行狀態)就需要從阻塞隊列移除任務,並嘗試判斷線程是否全部執行完畢。同時執行拒絕策略。
                    reject(command);
                else if (workerCountOf(recheck) == 0)  //如果當前線程池為空就新創建一個線程並執行。
                    addWorker(null, false);
            }
            else if (!addWorker(command, false)) //如果在第三步的判斷為非運行狀態,嘗試新建線程,如果失敗則執行拒絕策略
                reject(command);
    }
    

      


    線程池的關閉
    pool.shutdown();
    while(!pool.isTerminated()){

    }


並發7-線程池