1. 程式人生 > 實用技巧 >JUC之執行緒池-三大方法-七大引數-四種拒絕策略

JUC之執行緒池-三大方法-七大引數-四種拒絕策略

執行緒池:重點 三大方法 七大引數 四種拒絕策略

使用池化技術的理由:
我們的程式伴隨著建立銷燬執行緒十分浪費資源,
所以使用執行緒池,先建立執行緒,隨用隨取,用完歸還
簡單來說就是節約了資源。

使用執行緒池的好處:節省資源(最大併發執行緒數可控);提高了響應速度;方便管理


三大方法:
1.newFixedThreadPool(執行緒數):建立指定數量執行緒的執行緒池
2.newSingleThreadExecutor():建立單執行緒的執行緒池
3.newCacheThreadPool():隨著請求的增多執行緒也隨之建立,遇強則強

我們之前都是用Executors建立執行緒池的,但是到了後期強制不可以用
因此現在用ThreadPoolExecutor建立執行緒池
為什麼不能使用Executors建立執行緒池呢?
1.FixedThreadPool和SingleThreadPool允許的請求佇列的長度很大,約為21億,
所以可能堆積大量的請求,導致oom
2.CachedThreadPool允許建立的執行緒數量很大,可能會導致建立大量的執行緒,從而導致oom
程式碼如下:
public static void main(String[] args) {


// 三大方法之一:建立指定的執行緒數
ExecutorService threadPool = Executors.newFixedThreadPool(5);

//三大方法之二:建立單個執行緒
//ExecutorService threadPool = Executors.newSingleThreadExecutor();

//三大方法之三:隨之建立,遇強則強
//ExecutorService threadPool = Executors.newCachedThreadPool();
//使用執行緒池建立執行緒
try {
for (int i = 0; i < 100; i++) {
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//使用完畢,關閉執行緒池
threadPool.shutdown();
}
}

七大引數:
1.corePoolSize: 核心執行緒數,一直存活,即使執行緒數小於核心執行緒數的時候,
執行緒數有空閒,執行緒池也會建立新的執行緒。
2.maximumPoolSize:最大執行緒數,當執行緒數大於核心執行緒數的時候並且任務佇列已經滿了的時候,
執行緒池會建立新的執行緒,當執行緒數大於最大執行緒數的時候並且任務佇列已經滿了,
會丟擲異常。
3.keepAliveTime: 執行緒空閒時間:當執行緒的空閒時間達到keepAliveTime時,執行緒會退出,
直到執行緒數等於核心執行緒數,如果allowCoreThreadTimeout=true,
則會直到執行緒數為0。
4.TimeUnit unit 超時時間單位。

5.BlockingQueue<Runnable> workQueue:
阻塞佇列,任務佇列的容量。

6.ThreadFactory threadFactory:
執行緒工廠,基本不用設定。
7.RejectedExecutionHandler handler:
拒絕策略,任務拒絕處理器。

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;
}

四種拒絕策略:
1.new ThreadPoolExecutor..AbortPolicy():執行緒池滿了,還有執行緒想加入,不處理這個請求,跑出異常
2.new ThreadPoolExecutor.CallerRunsPolicy():如果任務被拒絕,則通過呼叫它執行緒執行此任務,哪來的回哪去
3.new ThreadPoolExecutor.DiscardPolicy():佇列滿了,丟掉任務,不會丟擲異常
4.new ThreadPoolExecutor.DiscardOldestPolicy():佇列滿了,嘗試去和最早的競爭,不會丟擲異常

IO密集型,CPU密集型:(調優)
public static void main(String[] args) {
// 自定義執行緒池!工作 ThreadPoolExecutor
// 最大執行緒到底該如何定義
// 1、CPU 密集型,幾核,就是幾,可以保持CPu的效率最高!
// 2、IO 密集型 > 判斷你程式中十分耗IO的執行緒,
// 程式 15個大型任務 io十分佔用資源!
// 獲取CPU的核數
System.out.println(Runtime.getRuntime().availableProcessors());
ExecutorService threadPool = new ThreadPoolExecutor(
2,
Runtime.getRuntime().availableProcessors(),
3,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardOldestPolicy()); //佇列滿了,嘗試去和
最早的競爭,也不會丟擲異常!
try {
// 最大承載:Deque + max
// 超過 RejectedExecutionException
for (int i = 1; i <= 9; i++) {
// 使用了執行緒池之後,使用執行緒池來建立執行緒
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+" ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 執行緒池用完,程式結束,關閉執行緒池
threadPool.shutdown();
}
}