執行緒池相關複習

isccai發表於2020-12-25

等待喚醒機制

  • 執行緒間通訊:多個執行緒在處理同一個資源,但是處理的動作(執行緒的任務)卻不相同。
    1. 為什麼要處理執行緒間通訊:
      多個執行緒併發執行時,在預設情況下CPU是隨機切換執行緒的,當我們需要多個執行緒來共同完成一件任務,並且我們希望他們有規律的執行,那麼多執行緒之間需要一些協調通訊,以此來幫我們達到多執行緒共同操作一份資料。
    2. 那麼執行緒之間是如何保證通訊有效利用資源呢?
      多個執行緒在處理同一個資源,並且任務不同時,需要執行緒通訊來幫助解決執行緒之間對同一個變數的使用或操作,就是多個執行緒在操作同一份資料時,避免對同一共享變數的爭奪。也就是我們需要通過一定的手段使各個執行緒能有效的利用資源,而這種手段就是–等待喚醒機制
    3. 那麼什麼事等待喚醒機制呢?
      • 這是多個執行緒間的一種協作機制。談到執行緒我們經常想到的是執行緒間的競爭,比如去爭奪鎖,但是不僅僅是競爭,執行緒之間也會有協作機制。
      • 在一個執行緒進行了規定操作後,就進入等待狀態(wait),等待其他執行緒執行完他們的指定程式碼後,再將其喚醒(notify);在有多個執行緒進行等待時,如果需要可以使用notifyAll來喚醒所有的等待執行緒。
      • wait/notify就是執行緒間的一種協作機制。

執行緒池

1. 執行緒池思想概述
我們使用執行緒的時候就去建立一個執行緒這樣實現起來確實非常方便,但是有一個問題:
如果併發的執行緒數量很多,並且每個執行緒都是執行一個時間很短的任務就結束了,這樣頻繁建立執行緒就會大大降低系統的效率,因為頻繁建立執行緒和消費執行緒需要時間。但是如果有一種辦法是的執行緒可以複用,就是執行完一個任務,並不銷燬,而是可以繼續執行其他任務,這樣能大大提高我們的工作效率。資料庫的連線池也是這種思想。
2. 執行緒池概念
執行緒池:就是一個容納多個執行緒的容器,其中的執行緒可以反覆使用,省去了頻繁建立執行緒物件的操作,無需反覆建立執行緒而消耗過多資源。
優點
1. 減少了建立和銷燬執行緒的次數,每個工作執行緒都可以被重複利用,可執行多個任務。
2. 提高響應速度。當任務到達時,任務可以不需要等到執行緒建立就能立即執行。
3. 提高執行緒的可管理性。根據系統的承受能力,調整執行緒池中工作執行緒的數目,防止因為消耗過多的記憶體,而把伺服器累趴下(每個執行緒需要大約1MB記憶體,執行緒開的越多,消耗的記憶體就越大,最後當機)。
3. 執行緒池的使用
Java執行緒池的頂級介面是java.util.concurrent.Executor,但是嚴格意義上講Executor並不是一個執行緒池,而只是一個執行執行緒的工具。真正的執行緒池介面是java.util.concurrent.ExecutorService。
要配置一個執行緒池是比較複雜的,尤其是對於執行緒池的原理不是很清楚的情況下,有可能配置的執行緒池不是比較優的,因此在java.util.concurrent.Executors執行緒工廠裡面提供了一些靜態工廠,生成一些常用的執行緒池。官方建議使用Executor工程類來建立執行緒池物件。

  • Executors類中有個建立執行緒池的方法如下:
    1. public static ExecutorService newFixedThreadPool(int nThreads):返回執行緒池物件。建立的是有界執行緒池,也就是池中的執行緒個數可以指定最大數量(方法引數)。
    2. public Future<?> submit(Runnable task):獲取執行緒池中的某一個物件,並執行
      *** 使用執行緒池中執行緒物件的步驟**:
      1. 建立執行緒池物件
      2. 建立Runnable介面子類物件
      3. 提交Runnable介面子類物件
      4. 關閉執行緒池(一般不做)
public class ThreadPoolDemo {
public static void main(String[] args) {
// 建立執行緒池物件
ExecutorService service = Executors.newFixedThreadPool(2);//包含2個執行緒物件
// 建立Runnable例項物件
MyRunnable r = new MyRunnable();
//自己建立執行緒物件的方式
// Thread t = new Thread(r);
// t.start(); ‐‐‐> 呼叫MyRunnable中的run()
// 從執行緒池中獲取執行緒物件,然後呼叫MyRunnable中的run()
service.submit(r);
// 再獲取個執行緒物件,呼叫MyRunnable中的run()
service.submit(r);
service.submit(r);
// 注意:submit方法呼叫結束後,程式並不終止,是因為執行緒池控制了執行緒的關閉。
// 將使用完的執行緒又歸還到了執行緒池中
// 關閉執行緒池
//service.shutdown();
}
}```
	

相關文章