概念:多個執行緒在處理同乙個資源,但是處理的動作(執行緒的任務)卻不相同。
為什麼要處理執行緒間通訊:
多個執行緒併發執行時, 在預設情況下cpu是隨機切換執行緒的,當我們需要多個執行緒來共同完成一件任務,並且我們希望他們有規律的執行, 那麼多執行緒之間需要一些協調通訊,以此來幫我們達到多執行緒共同操作乙份資料。
如何保證執行緒間通訊有效利用資源:
多個執行緒在處理同乙個資源,並且任務不同時,需要執行緒通訊來幫助解決執行緒之間對同乙個變數的使用或操作。 就是多個執行緒在操作同乙份資料時, 避免對同一共享變數的爭奪。也就是我們需要通過一定的手段使各個執行緒能有效的利用資源。而這種手段即—— 等待喚醒機制。
什麼是等待喚醒機制
這是多個執行緒間的一種協作機制。談到執行緒我們經常想到的是執行緒間的競爭(race),比如去爭奪鎖,但這並不是故事的全部,執行緒間也會有協作機制。就好比在公司裡你和你的同事們,你們可能存在在晉公升時的競爭,但更多時候你們更多是一起合作以完成某些任務。
就是在乙個執行緒進行了規定操作後,就進入等待狀態(wait()), 等待其他執行緒執行完他們的指定**過後 再將其喚醒(notify());在有多個執行緒進行等待時, 如果需要,可以使用 **notifyall()**來喚醒所有的等待執行緒。 wait/notify 就是執行緒間的一種協作機制。
等待喚醒中的方法
wait:執行緒不再活動,不再參與排程,進入 wait set 中,因此不會浪費 cpu 資源,也不會去競爭鎖了,這時的執行緒狀態即是 waiting。它還要執行乙個特別的動作,也即是「通知(notify)」在這個物件上等待的執行緒從wait set 中釋放出來,重新進入到排程佇列(ready queue)中
notify:則選取所通知物件的 wait set 中的乙個執行緒釋放;例如,餐館有空位置後,等候就餐最久的顧客最先入座。
notifyall:則釋放所通知物件的 wait set 上的全部執行緒。
總結如下:
如果能獲取鎖,執行緒就從 waiting 狀態變成 runnable 狀態;
否則,從 wait set 出來,又進入 entry set,執行緒就從 waiting 狀態又變成 blocked 狀態
呼叫wait和notify方法需要注意的細節
wait方法與notify方法必須要由同乙個鎖物件呼叫。因為:對應的鎖物件可以通過notify喚醒使用同乙個鎖物件呼叫的wait方法後的執行緒。
wait方法與notify方法是屬於object類的方法的。因為:鎖物件可以是任意物件,而任意物件的所屬類都是繼承了object類的。
wait方法與notify方法必須要在同步**塊或者是同步函式中使用。因為:必須要通過鎖物件呼叫這2個方法。
執行緒池思想概述
執行緒池:其實就是乙個容納多個執行緒的容器,其中的執行緒可以反覆使用,省去了頻繁建立執行緒物件的操作,無需反覆建立執行緒而消耗過多資源。
合理利用執行緒池能夠帶來三個好處:
降低資源消耗。減少了建立和銷毀執行緒的次數,每個工作執行緒都可以被重複利用,可執行多個任務。
提高響應速度。當任務到達時,任務可以不需要的等到執行緒建立就能立即執行。
提高執行緒的可管理性。可以根據系統的承受能力,調整執行緒池中工作線執行緒的數目,防止因為消耗過多的記憶體,而把伺服器累趴下(每個執行緒需要大約1mb記憶體,執行緒開的越多,消耗的記憶體也就越大,最後宕機)。
executors類中有個建立執行緒池的方法如下:
public static executorservice newfixedthreadpool(int nthreads) :返回執行緒池物件。(建立的是有界線程池,也就是池中的執行緒個數可以指定最大數量)
獲取到了乙個執行緒池executorservice 物件,那麼怎麼使用呢,在這裡定義了乙個使用執行緒池物件的方法如下:
public future<?> submit(runnable task) :獲取執行緒池中的某乙個執行緒物件,並執行future介面:用來記錄執行緒任務執行完畢後產生的結果。執行緒池建立與使用。
使用執行緒池中線程物件的步驟:
建立執行緒池物件。
建立runnable介面子類物件。(task)
提交runnable介面子類物件。(take task)
關閉執行緒池(一般不做)。
lambda表示式:在數學中,函式就是有輸入量、輸出量的一套計算方案,也就是「拿什麼東西做什麼事情」。相對而言,物件導向過分強調「必須通過物件的形式來做事情」,而函式式思想則盡量忽略物件導向的複雜語法——強調做什麼,而不是以什麼形式做。
使用實現類
public thread(runnable target)
public class runnableimpl implements runnable
}
使用匿名內部類
public class demo04threadnameless
}).start();
}}
匿名內部類的好處與弊端
一方面,匿名內部類可以幫我們省去實現類的定義;另一方面,匿名內部類的語法——確實太複雜了!
語義分析
仔細分析該**中的語義, runnable 介面只有乙個 run 方法的定義:
public abstract void run();
無引數:不需要任何條件即可執行該方案。
無返回值:該方案不產生任何結果。
**塊(方法體):該方案的具體執行步驟。
lambda表示式的標準格式為:(引數型別 引數名稱) ‐>
格式說明:
小括號內的語法與傳統方法引數列表一致:無引數則留空;多個引數則用逗號分隔。
-> 是新引入的語法格式,代表指向動作。
大括號內的語法與傳統方法體要求基本一致。
省略規則
在lambda標準格式的基礎上,使用省略寫法的規則為:
小括號內引數的型別可以省略;
如果小括號內有且僅有乙個參,則小括號可以省略;
如果大括號內有且僅有乙個語句,則無論是否有返回值,都可以省略大括號、return關鍵字及語句分號。
備註:掌握這些省略規則後,請對應地回顧本章開頭的多執行緒案例
lambda的使用前提
lambda的語法非常簡潔,完全沒有物件導向複雜的束縛。但是使用時有幾個問題需要特別注意:
使用lambda必須具有介面,且要求介面中有且僅有乙個抽象方法。
無論是jdk內建的 runnable 、 comparator 介面還是自定義的介面,只有當介面中的抽象方法存在且唯一時,才可以使用lambda。
使用lambda必須具有上下文推斷。
也就是方法的引數或區域性變數型別必須為lambda對應的介面型別,才能使用lambda作為該介面的例項。
備註:有且僅有乙個抽象方法的介面,稱為「函式式介面
Java執行緒池
executors類詳解 此包中所定義的 executor executorservice scheduledexecutorservice threadfactory 和 callable 類的工廠和實用方法。此類支援以下各種方法 建立並返回設定有常用配置字串的 executorservice 的...
Java執行緒池
一 執行緒池 單執行緒 public static void runsinglethreadpool public static void runsinglethreadpoolwithfactory private static class mythreadfactory implements t...
java 執行緒池
1.執行緒池的作用 限制系統中執行執行緒的數量 2.為什麼要用執行緒池 2.1.減少了建立和銷毀執行緒的次數,每個工作執行緒都可以被重複利用,可執行多個任務.2.2 可以根據系統的承受能力,調整執行緒池中工作線執行緒的數目,防止因為消耗過多的記憶體,而把伺服器累趴下。3.執行緒池介面類 3.1 ex...