第四章Java併發編程基礎
前言:之前寫了前三章的筆記,雖然寫筆記讓我的閱讀慢下來可以更仔細的反覆閱讀某些部分,但是現在重看筆記,卻覺得沒有營養,一是書上內容居多,自己的想法不多,二是內容雜亂沒有整體思路。反觀書本,對我來說直觀的感受是,這不是一本適合基礎的人看的書,但有些內容對於瞭解的又過於基礎,這點體現在與作者想要透徹的寫原理,但是又由於篇幅限制有些地方卻草草略過,這對於我這種程度閱讀者來說明顯有點喫力,但這或許也是本書的特點,能迫使你自己動手去完善。所以,之後的章節會盡量少的貼書中的內容,多放些書中沒有而自己查的資料。再次提醒自己,認真對待!
4.1線程簡介
面試中面試官會問:說說Java線程吧。
我現在嘗試不看書,說說自己的認識:線程是操作系統調度的最小單元,一個應用程序會啓動多個線程,每個線程都有自己的棧內存,也就是說線程是相互獨立的。線程操作着自己所運行代碼的局部變量,方法參數,他們之間互不影響。線程間的通信通過共享內存機制進行,把內存中的變量拷貝到自己的工作空間之後寫會內存,當然這種方式會有問題,於是爲了避免線程在操作系統上的數據競爭等等,出現與我們預期功能不一致的問題,出現了很多控制方法如 volatile、加鎖、CAS、hapen-before規則或者一些高級用法,使得我們線程運行的不確定性能在我們的控制範圍內。
之後看書查資料:線程和進程明白講線程還是需要提到進程,需要擴張聯繫,這點需要加強。
-
使用線程優勢:執行快,響應快,資源利用率(這是相互的,線程需要資源,資源需要利用)
-
使用線程缺點:複雜,不確定性,安全
線程優先級
有優先級,操作系統不認。我猜可能是管理線程優先級的代價會比管理代碼的代價來的大。書上有測試程序,但沒興趣跑。
線程狀態
線程狀態很重要,在分析問題的時候要懂得看。
在書中的代碼
public class ThreadState {
public static void main(String[] args) {
new Thread(new TimeWaiting(),"TimeWaitingThread").start();
new Thread(new Waiting(),"WaitingThread").start();
new Thread(new Blocked(),"BlockedThread - 1").start();
new Thread(new Blocked(),"BlockedThread - 2").start();
}
static class TimeWaiting implements Runnable{
@Override
public void run() {
while (true) {
try {
TimeUnit.SECONDS.sleep(100);
} catch (InterruptedException e) {
}
}
}
}
static class Waiting implements Runnable{
@Override
public void run() {
while (true) {
synchronized (Waiting.class){
try {
Waiting.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
static class Blocked implements Runnable{
@Override
public void run() {
synchronized (Blocked.class) {
while (true) {
try {
TimeUnit.SECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
運行
終端輸入jsp(查看在Java進程信息,windows在Java目錄下bin裏找)
輸出Java進程號 類名
終端輸入 jstack 剛纔的進程號
Java中
運行
和就緒
兩個狀態合併稱爲運行狀態
這裏還是引用資料 Java線程狀態切換以及核心方法
4.2 啓動和終止線程
在初始化的代碼中可以看到 如果在守護線程中創建線程,那麼創建的線程將繼承父線程的屬性也將編程守護線程。
代碼不貼,是Thread.java
的init
方法。
中斷概念很重要,書中我看內容並不多,所以要自己補充。
JAVA中斷機制詳解
suspend()
、resume()
、stop()
廢棄
線程的終止使用中斷機制,在中斷後我們可以有後續操作比如回滾什麼的。
4.3 線程間通信
只說很重要的一點:
notify()
或 notifyAll()
方法調用後,等待線程依舊不會從wait()返回,需要調用上述方法的線程釋放鎖之後,等待線程才***有機會***從wait()返回。
等待通知的經典範式
等待方
- 1 獲取對象鎖
- 2 如果條件不滿足調用對象的wait()方法,被通知後仍要檢查條件。
- 3 條件滿足則執行對應的邏輯
...
synchronized(鎖對象){
while(條件){
對象.wait();
}
後續處理
}
例如生產者消費者代碼片段
...
synchronized(queue){
while(queue.size() == maxSize){
try {
System.out .println("Queue is full, Producer[" + name + "] thread waiting for " + "consumer to take something from queue.");
queue.wait();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
...
通知方
- 1獲得對象鎖
- 2改變條件
- 通知所有等待在對象上的線程
...
synchronized(鎖對象){
改變條件
對象.notifyAll();
}
例如生產者消費者代碼片段
...
synchronized(queue){
int x = queue.poll();
System.out.println("[" + name + "] Consuming value : " + x);
queue.notifyAll();
}
...
構建線程安全類的一種法方 棧封閉
徹底理解ThreadLocal
線程應用實例
代碼最好自己敲一邊理解
最後想說一句——紙上得來終覺淺,絕知此事要躬行.