java線程池及創建多少線程合適


  java線程池

  1、以下是ThreadPoolExecutor參數完備構造方法:

    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,threadFactory threadFactory, RejectedExecutionHandler handler);

 

    corePoolSize:線程池的大小,當剛開始創建線程池時,線程數為0,當線程池中線程數量多於corePoolSize時會存於緩存隊列

    maxinumPoolSize:線程池容納的最多線程數量

    keepAliveTime:空閑線程的存活時間,一般情況下是當前線程線程數超過線程池大小,才會進行回收

    unit:keepAliveTime的事件單位

    workQueue:緩存隊列

      ArrayBlockingQueue:基於數組的先進先出隊列,此隊列創建時必須指定大小;

      LinkedBlockingQueue:基於鏈表的先進先出隊列,如果創建時沒有指定此隊列大小,則默認為Integer.MAX_VALUE;

      synchronousQueue:這個隊列比較特殊,它不會保存提交的任務,而是將直接新建一個線程來執行新來的任務。

    threadFactory:通過這個參數你可以自定義如何創建線程,例如你可以給線程指定一個有意義的名字。

    handler:通過這個參數你可以自定義任務的拒絕策略。如果線程池中所有的線程都在忙碌,並且工作隊列也滿了(前提是工作隊列是有界隊列),那么此時提交任務,線程池就會拒絕接收。至於拒絕的策略,你可以通過 handler 這個參數來指定。

      ThreadPoolExecutor 已經提供了以下 4 種策略。

      

  CallerRunsPolicy:提交任務的線程自己去執行該任務。

        AbortPolicy:默認的拒絕策略,會 throws RejectedExecutionException。

        DiscardPolicy:直接丟棄任務,沒有任何異常拋出。

        DiscardOldestPolicy:丟棄最老的任務,其實就是把最早進入工作隊列的任務丟棄,然后把新任務加入到工作隊列。

  執行流程:

      線程池創建線程,會判斷當前線程數是否大於corePoolSize。

      如果大於則存在緩存隊列,緩沖隊列存滿后會繼續創建線程直到maximumPoolSize,拋出拒絕的異常。

      如果小於則創建線程,執行任務,執行完后會從緩存隊列中取任務再執行

  2、封裝線程池

  

public static ExecutorService newFixedThreadPool(int nThreads) {

      return new ThreadPoolExecutor(nThreads, nThreads,

                                  0L, TimeUnit.MILLISECONDS,

                                  new LinkedBlockingQueue<Runnable>());

  }

  //創建的線程池corePoolSize和maximumPoolSize值是相等的,它使用的LinkedBlockingQueue;

 

  

public static ExecutorService newSingleThreadExecutor() {

      return new FinalizableDelegatedExecutorService

        (new ThreadPoolExecutor(1, 1,

                                0L, TimeUnit.MILLISECONDS,

                                new LinkedBlockingQueue<Runnable>()));

}

//將corePoolSize和maximumPoolSize都設置為1,也使用的LinkedBlockingQueue

 

public static ExecutorService newCachedThreadPool() {

    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

                                  60L, TimeUnit.SECONDS,

                                  new SynchronousQueue<Runnable>());

}

//將corePoolSize設置為0,將maximumPoolSize設置為Integer.MAX_VALUE,使用的SynchronousQueue,也就是說來了任務就創建線程運行,當線程空閑超過60秒,就銷毀線程

  日常工作中不建議使用以上線程池:

    1)newFixedThreadPool 和 newSingleThreadExecutor:主要問題是堆積的請求處理隊列可能會耗費非常大的內存,甚至 OOM。

    2)newCachedThreadPool 和 newScheduledThreadPool:主要問題是線程數最大數是 Integer.MAX_VALUE,可能會創建數量非常多的線程,甚至 OOM。

 

 

  創建多少線程合適呢?

    創建多少線程合適,要看多線程具體的應用場景。我們的程序一般都是 CPU 計算和 I/O 操作交叉執行的,由於 I/O 設備的速度相對於 CPU 來說都很慢,所以大部分情況下,I/O 操作執行的時間相對於 CPU 計算來說都非常長,這種場景我們一般都稱為 I/O 密集型計算;和 I/O 密集型計算相對的就是 CPU 密集型計算了,CPU 密集型計算大部分場景下都是純 CPU 計算。I/O 密集型程序和 CPU 密集型程序,計算最佳線程數的方法是不同的。

    對於CPU密集型來說,多線程主要目的是提成CPU利用率,保持和CPU核數一致即可。不過在工程上,,線程的數量一般會設置為“CPU 核數 +1”,這樣的話,當線程因為偶爾的內存頁失效或其他原因導致阻塞時,這個額外的線程可以頂上,從而保證 CPU 的利用率。

    對於IO密集型來說,一般是最佳線程數 =CPU 核數 * [ 1 +(I/O 耗時 / CPU 耗時)]

    總之上述僅可代表項目初始時設定的線程數量,后續隨着實際應用場景進行調整優化

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM