日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【多线程】线程池的创建和参数设定

發布時間:2023/12/20 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【多线程】线程池的创建和参数设定 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

為什么要使用線程池

在日常開發中為了提高代碼運行效率,或多或少會用線程去執行異步任務,線程的創建和銷毀是需要占用一定資源的。

首先我們看一下一個線程的創建步驟:

  • 為線程堆棧分配和初始化大量內存塊
  • 需要進行系統調用,以便在主機OS中創建/注冊本機線程
  • 描述符需要創建、初始化并添加到JVM內部數據結構中

池化技術的出現是為了重復利用已存在的線程,避免了頻繁的創建和銷毀。

線程池的初始化及參數

注意:線程池必須手動通過 ThreadPoolExecutor 的構造函數來聲明,避免使用Executors 類的 newFixedThreadPool 和 newCachedThreadPool ,因為可能會有 OOM 的風險。

看下ThreadPoolExecutor中的構造方法

/*** Creates a new {@code ThreadPoolExecutor} with the given initial* parameters.** @param corePoolSize the number of threads to keep in the pool, even* if they are idle, unless {@code allowCoreThreadTimeOut} is set* @param maximumPoolSize the maximum number of threads to allow in the* pool* @param keepAliveTime when the number of threads is greater than* the core, this is the maximum time that excess idle threads* will wait for new tasks before terminating.* @param unit the time unit for the {@code keepAliveTime} argument* @param workQueue the queue to use for holding tasks before they are* executed. This queue will hold only the {@code Runnable}* tasks submitted by the {@code execute} method.* @param threadFactory the factory to use when the executor* creates a new thread* @param handler the handler to use when execution is blocked* because the thread bounds and queue capacities are reached* @throws IllegalArgumentException if one of the following holds:<br>* {@code corePoolSize < 0}<br>* {@code keepAliveTime < 0}<br>* {@code maximumPoolSize <= 0}<br>* {@code maximumPoolSize < corePoolSize}* @throws NullPointerException if {@code workQueue}* or {@code threadFactory} or {@code handler} is null*/public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;}

corePoolSize 核心線程數

核心線程:要保留在池中的線??程數,即使它們處于空閑狀態,線程池創建的時候是空的,隨著任務的調用,逐步增加到核心線程數的大小。當任務進來時,如果有核心線程空閑,則優先使用核心線程。

如何設計核心線程池的數量:

  • 如果是CPU密集型應用,則線程池大小設置為N+1 (N為CPU總核數)
  • 如果是IO密集型應用,則線程池大小設置為2N+1 (N為CPU總核數)
  • 線程等待時間(IO)所占比例越高,需要越多線程。
  • 線程CPU時間所占比例越高,需要越少線程。

1. 題外話:cpu密集型和IO密集型是什么

是任務、方法的類型

1. cpu密集型(計算密集型、cpu高了)

處理運算時間比較長,系統運行的大部分狀況是CPU Loading 100%,不太需要訪問I/O設備

1. 例如

計算圓周率、對視頻進行高清解碼

2. 要注意什么

盡量避免CPU的切換,任務同時進行的數量 = CPU的核心數

1. IO密集型

IO的速度遠遠低于CPU和內存的速度,cpu性能好,處理運算時間比較短,大部分的狀況是CPU在等I/O (硬盤/內存) 的讀/寫操作

1. 例如

Web應用

2. 要注意什么

可以充分利用CPU的資源,但不能開啟任務數量太多,一般情況:任務同時進行的數量 = 2*CPU的核心數

maximumPoolSize 最大線程數

池中允許的最大線程數

keepAliveTime 非核心線程的活躍時間

當線程數大于核心數時,非核心線程如果過了keepAliveTime長時間還沒有執行新的任務,則銷毀線程。

unit 單位

是keepAliveTime的時間單位

workQueue 隊列

用于在執行任務之前保存任務的隊列。該隊列將僅保存由 {@code execute} 方法提交的 {@code Runnable} 任務。

workQueue的類型為BlockingQueue,通常可以取下面三種類型:

隊列的種類:

  • ArrayBlockingQueue 有界任務隊列

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

  • LinkedBlockingQueue 無界任務隊列

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

  • SynchronousQueue 同步隊列

一個不存儲元素的阻塞隊列,每個插入操作必須等到另一個線程調用移除操作,否則插入操作一直處于阻塞狀態,吞吐量通常要高于LinkedBlockingQuene

  • PriorityBlockingQueue 優先級隊列

一個支持優先級的無界阻塞隊列,可以通過其構造方法,自定義排序的規則,默認按照首字母從小到大排序,生產的時候隨便,消費的時候會按照優先級消費

public PriorityBlockingQueue(int initialCapacity,Comparator<? super E> comparator) {if (initialCapacity < 1)throw new IllegalArgumentException();this.lock = new ReentrantLock();this.notEmpty = lock.newCondition();this.comparator = comparator;this.queue = new Object[initialCapacity];}

threadFactory 線程工廠

工廠類,創建新線程時使用的工廠

handler 飽和策略

由于達到線程邊界和隊列容量而阻塞執行時要使用的處理程序,默認是AbordPolicy,表示無法處理新任務,并拋出 RejectedExecutionException 異常

1. AbortPolicy(拒絕拋出異常)

/*** A handler for rejected tasks that throws a* {@code RejectedExecutionException}.*/public static class AbortPolicy implements RejectedExecutionHandler {}

丟棄任務并拋出RejectedExecutionException異常,默認策略

如果是比較關鍵的業務,推薦使用此拒絕策略,這樣子在系統不能承載更大的并發量的時候,能夠及時的通過異常發現。

2. CallerRunsPolicy(讓外面的線程去處理)

/*** A handler for rejected tasks that runs the rejected task* directly in the calling thread of the {@code execute} method,* unless the executor has been shut down, in which case the task* is discarded.*/public static class CallerRunsPolicy implements RejectedExecutionHandler {}

由調用線程(執行execute的線程)去處理該任務,如果調用線程關閉,則直接拋棄該任務

3. DiscardOldestPolicy(把最老的丟掉、喜新厭舊)

/*** A handler for rejected tasks that discards the oldest unhandled* request and then retries {@code execute}, unless the executor* is shut down, in which case the task is discarded.*/public static class DiscardOldestPolicy implements RejectedExecutionHandler {}

丟棄隊列最老的未執行的任務,然后重新提交被拒絕的這個任務(喜新厭舊的策略)

是否要采用此種拒絕策略,還得根據實際業務是否允許丟棄老任務來認真衡量。

4. DiscardPolicy(偷偷的拋棄,不拋異常)

/*** A handler for rejected tasks that silently discards the* rejected task.*/public static class DiscardPolicy implements RejectedExecutionHandler {}

直接拋棄該任務,不會拋出異常。使用該策略,可能會使我們無法發現系統的異常狀態。建議是一些無關緊要的業務采用此策略。

1.例如

閱讀量、點擊量這些高頻的但不需要很精確操作

總結

以上是生活随笔為你收集整理的【多线程】线程池的创建和参数设定的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。