二、JUC之線程池
二、JUC之線程池
- 二、JUC之線程池
-
-
- 1、為什麼用線程池
- 2、線程池的使用
-
- 1、Executors.newFixedThreadPool(int)
- 2、Executors.newSingleThreadExecutor()
- 3、Executors.newCachedThreadPool()
- 3、ThreadPoolExecutor底層原理
- 4、拒絕政策?生産中如設定合理參數
-
- 1、線程池的拒絕政策
- 2、JDK内置的拒絕政策
- 5、超級大坑 在工作中單一的/固定數的/可變的三種建立線程池的方法哪個用的多?
- 6、自定義線程池
- 7、BlockingQueue阻塞隊列
-
- 1、棧與隊列
- 2、阻塞隊列
- 3、種類分析
- 4、BlockingQueue核心方法
- 更多内容:
-
1、為什麼用線程池
線程池的優勢:
線程池做的工作主要是控制運作的線程數量,處理過程中将任務放入隊列,然後線上程建立後啟動這些任務,如果線程數量超過了最大數量,超出數量的線程排隊等候,等其他線程執行完畢,再從隊列中取出任務來執行。
它的主要特點為:線程複用;控制最大并發數;管理線程。
第一:降低資源消耗。通過重複利用已建立的線程降低線程建立和銷毀造成的銷耗。
第二:提高響應速度。當任務到達時,任務可以不需要等待線程建立就能立即執行。
第三:提高線程的可管理性。線程是稀缺資源,如果無限制的建立,不僅會銷耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的配置設定,調優和監控
2、線程池的使用
1、Executors.newFixedThreadPool(int)
newFixedThreadPool建立的線程池corePoolSize和maximumPoolSize值是相等的,它使用的是LinkedBlockingQueue執行長期任務性能好,建立一個線程池,一池有N個固定的線程,有固定線程數的線程
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
2、Executors.newSingleThreadExecutor()
newSingleThreadExecutor 建立的線程池corePoolSize和maximumPoolSize值都是1,它使用的是LinkedBlockingQueue一個任務一個任務的執行,一池一線程
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
3、Executors.newCachedThreadPool()
newCachedThreadPool建立的線程池将corePoolSize設定為0,将maximumPoolSize設定為Integer.MAX_VALUE,它使用的是SynchronousQueue,也就是說來了任務就建立線程運作,當線程空閑超過60秒,就銷毀線程。
執行很多短期異步任務,線程池根據需要建立新線程,但在先前建構的線程可用時将重用它們。可擴容,遇強則強
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 線程池
* Arrays
* Collections
* Executors
*/
public class MyThreadPoolDemo {
public static void main(String[] args) {
//List list = new ArrayList();
//List list = Arrays.asList("a","b");
//固定數的線程池,一池五線程
// ExecutorService threadPool = Executors.newFixedThreadPool(5); //一個銀行網點,5個受理業務的視窗
// ExecutorService threadPool = Executors.newSingleThreadExecutor(); //一個銀行網點,1個受理業務的視窗
ExecutorService threadPool = Executors.newCachedThreadPool(); //一個銀行網點,可擴充受理業務的視窗
//10個顧客請求
try {
for (int i = 1; i <=10; i++) {
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"\t 辦理業務");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
}
3、ThreadPoolExecutor底層原理
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:線程池中的常駐核心線程數
- maximumPoolSize:線程池中能夠容納同時執行的最大線程數,此值必須大于等于1
- keepAliveTime:多餘的空閑線程的存活時間,目前池中線程數量超過corePoolSize時,當空閑時間,達到keepAliveTime時,多餘線程會被銷毀直到隻剩下corePoolSize個線程為止
- unit:keepAliveTime的機關
- workQueue:任務隊列,被送出但尚未被執行的任務
- threadFactory:表示生成線程池中工作線程的線程工廠,用于建立線程,一般預設的即可
- handler:拒絕政策,表示當隊列滿了,并且工作線程大于等于線程池的最大線程數(maximumPoolSize)時如何來拒絕請求執行的runnable的政策
1、在建立了線程池後,開始等待請求。
2、當調用execute()方法添加一個請求任務時,線程池會做出如下判斷:
2.1如果正在運作的線程數量小于corePoolSize,那麼馬上建立線程運作這個任務;
2.2如果正在運作的線程數量大于或等于corePoolSize,那麼将這個任務放入隊列;
2.3如果這個時候隊列滿了且正在運作的線程數量還小于maximumPoolSize,那麼還是要建立非核心線程立刻運作這個任務;
2.4如果隊列滿了且正在運作的線程數量大于或等于maximumPoolSize,那麼線程池會啟動飽和拒絕政策來執行。
3、當一個線程完成任務時,它會從隊列中取下一個任務來執行。
4、當一個線程無事可做超過一定的時間(keepAliveTime)時,線程會判斷:
如果目前運作的線程數大于corePoolSize,那麼這個線程就被停掉。
是以線程池的所有任務完成後,它最終會收縮到corePoolSize的大小。
4、拒絕政策?生産中如設定合理參數
1、線程池的拒絕政策
等待隊列已經排滿了,再也塞不下新任務了,同時,線程池中的max線程也達到了,無法繼續為新任務服務。這個是時候我們就需要拒絕政策機制合理的處理這個問題。
2、JDK内置的拒絕政策
AbortPolicy(預設):直接抛出RejectedExecutionException異常阻止系統正常運作
CallerRunsPolicy:“調用者運作”一種調節機制,該政策既不會抛棄任務,也不會抛出異常,而是将某些任務回退到調用者,進而降低新任務的流量。
DiscardOldestPolicy:抛棄隊列中等待最久的任務,然後把目前任務加入隊列中嘗試再次送出目前任務。
DiscardPolicy:該政策默默地丢棄無法處理的任務,不予任何處理也不抛出異常。如果允許任務丢失,這是最好的一種政策。
以上内置拒絕政策均實作了RejectedExecutionHandle接口
5、超級大坑 在工作中單一的/固定數的/可變的三種建立線程池的方法哪個用的多?
答案是一個都不用,我們工作中隻能使用自定義的
6、自定義線程池
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
/**
* 線程池
* Arrays
* Collections
* Executors
*/
public class MyThreadPoolDemo {
public static void main(String[] args) {
ExecutorService threadPool = new ThreadPoolExecutor(
2,
5,
2L,
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(3),
Executors.defaultThreadFactory(),
//new ThreadPoolExecutor.AbortPolicy()
//new ThreadPoolExecutor.CallerRunsPolicy()
//new ThreadPoolExecutor.DiscardOldestPolicy()
new ThreadPoolExecutor.DiscardOldestPolicy()
);
//10個顧客請求
try {
for (int i = 1; i <= 10; i++) {
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + "\t 辦理業務");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
private static void threadPool() {
//List list = new ArrayList();
//List list = Arrays.asList("a","b");
//固定數的線程池,一池五線程
// ExecutorService threadPool = Executors.newFixedThreadPool(5); //一個銀行網點,5個受理業務的視窗
// ExecutorService threadPool = Executors.newSingleThreadExecutor(); //一個銀行網點,1個受理業務的視窗
ExecutorService threadPool = Executors.newCachedThreadPool(); //一個銀行網點,可擴充受理業務的視窗
//10個顧客請求
try {
for (int i = 1; i <= 10; i++) {
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + "\t 辦理業務");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
}
7、BlockingQueue阻塞隊列
1、棧與隊列
棧:先進後出,後進先出
隊列:先進先出
2、阻塞隊列
阻塞:必須要阻塞/不得不阻塞
線程1往阻塞隊列裡添加元素,線程2從阻塞隊列裡移除元素
當隊列是空的,從隊列中擷取元素的操作将會被阻塞
當隊列是滿的,從隊列中添加元素的操作将會被阻塞
試圖從空的隊列中擷取元素的線程将會被阻塞,直到其他線程往空的隊列插入新的元素
試圖向已滿的隊列中添加新元素的線程将會被阻塞,直到其他線程從隊列中移除一個或多個元素或者完全清空,使隊列變得空閑起來并後續新增
3、種類分析
ArrayBlockingQueue:由數組結構組成的有界阻塞隊列。
LinkedBlockingQueue:由連結清單結構組成的有界(但大小預設值為integer.MAX_VALUE)阻塞隊列。
PriorityBlockingQueue:支援優先級排序的無界阻塞隊列。
DelayQueue:使用優先級隊列實作的延遲無界阻塞隊列。
SynchronousQueue:不存儲元素的阻塞隊列,也即單個元素的隊列。
LinkedTransferQueue:由連結清單組成的無界阻塞隊列。
LinkedBlockingDeque:由連結清單組成的雙向阻塞隊列。
4、BlockingQueue核心方法
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* 阻塞隊列
*/
public class BlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
// List list = new ArrayList();
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
//第一組
// System.out.println(blockingQueue.add("a"));
// System.out.println(blockingQueue.add("b"));
// System.out.println(blockingQueue.add("c"));
// System.out.println(blockingQueue.element());
//System.out.println(blockingQueue.add("x"));
// System.out.println(blockingQueue.remove());
// System.out.println(blockingQueue.remove());
// System.out.println(blockingQueue.remove());
// System.out.println(blockingQueue.remove());
// 第二組
// System.out.println(blockingQueue.offer("a"));
// System.out.println(blockingQueue.offer("b"));
// System.out.println(blockingQueue.offer("c"));
// System.out.println(blockingQueue.offer("x"));
// System.out.println(blockingQueue.poll());
// System.out.println(blockingQueue.poll());
// System.out.println(blockingQueue.poll());
// System.out.println(blockingQueue.poll());
// 第三組
// blockingQueue.put("a");
// blockingQueue.put("b");
// blockingQueue.put("c");
// //blockingQueue.put("x");
// System.out.println(blockingQueue.take());
// System.out.println(blockingQueue.take());
// System.out.println(blockingQueue.take());
// System.out.println(blockingQueue.take());
// 第四組
System.out.println(blockingQueue.offer("a"));
System.out.println(blockingQueue.offer("b"));
System.out.println(blockingQueue.offer("c"));
System.out.println(blockingQueue.offer("a",3L, TimeUnit.SECONDS));
}
}
下一篇:CompletableFuture
更多内容:
更多内容大家可以關注一下個人部落格網,https://blog.xueqimiao.com/,内容更豐富喔。
回複JUC可以擷取完整md文檔喔,謝謝關注。