Java程式設計師修煉之道—併發程式設計

i遇見你真好發表於2017-04-19
Java執行緒模型:
共享的、預設可見的可變狀態
搶佔式執行緒排程
所有執行緒可以很容易地共享同一程式中的物件。
能夠引用這些物件的任何執行緒都可以修改這些物件。
執行緒排程程式差不多任何時候都能在核心上調入或調出執行緒。
必須能調出執行時的方法,否則無限迴圈的方法會一直佔用CPU。
    然而這種不可預料的執行緒排程可能會導致方法“半途而廢”,並出現不一致的物件。某一執行緒對資料做出修改時,    
    會讓其他執行緒無法看到本應可見的修改。
為了保護脆弱的資料,物件可以被鎖住。

設計理念:
設計原則:安全性-併發型別安全性、活躍度、效能、可用性、重用性

保證執行緒安全性的常見方法:
儘可能限制子系統之間的通訊,隱藏資料對安全性非常有幫助。
儘可能保證子系統內部結構的確定性。比如說,即便子系統會以併發的、非確定性大的方式進行互動,子系統內部的設計也應該參照執行緒和物件的靜態知識。
採用客戶端應用必須遵守的策略方針。這個技巧強大,卻依賴使用者應用程式的合作程度,如果某個糟糕的應用不遵守規則,很難發現問題所在。
在文件中記錄所有要求的行為。

系統開銷之源
併發系統中的系統開銷是與生俱來:
鎖與監測、環境切換的次數、執行緒的個數、排程、記憶體的區域性性、演算法設計

同步與鎖
synchronized可以用在程式碼塊、方法,表明執行程式碼塊或方法之前必須取得合適的鎖。對於方法,意味著要去的物件例項鎖(對於靜態方法這是類鎖)。
對於程式碼塊,應該指明要取得哪個物件的鎖。
在任何一個物件的同步塊或方法中,每次只能有一個執行緒進入;如果其他執行緒試圖進入,JVM都會掛起它們。
無論其他執行緒試圖進入的是該物件的同一同步塊還是不同的同步塊,JVM都會如此處理。這種結構在併發理論中
被稱為臨界區。

不可變物件及構建器:必須在構造方法中初始化final域、構造器類必須是靜態內部類

併發工具包:java.util.current
原子類:java.util.concurrent.atomic
java.util.concurrent.automic中有幾個 名字以Automic開頭的類。它們的語義基本上和volatile一樣,只是封裝在一個API裡
,這個API包含為操作提供的適當的原子方法。

執行緒鎖:java.util.current.locks
鎖只有一種型別。。
對被鎖住物件的所有同步操作都是一樣的作用。
在同步程式碼塊或方法開始取得執行緒鎖。
在同步塊或方法結束時釋放執行緒鎖。
執行緒或者得到鎖,或者阻塞——沒有其他可能。
新增不同型別的鎖,比如讀取鎖和寫入鎖。
對鎖的阻塞沒有限制,即允許在一個方法中上鎖,在另一個方法中解鎖。
如果執行緒得不到鎖,比如鎖由另一個執行緒持有,就允許該執行緒後退或繼續執行,或者做點別的事情——運用tryLock()方法。
允許執行緒嘗試取鎖,並可以在超過等待時間後放棄。
關鍵是java.util.concurrent.locks中的Lock介面,及兩個實現類
ReentrantLock——本質與同步塊上的那種鎖是一樣的,但它要稍微靈活點。
ReentReadWrite——在需要讀取很多執行緒而寫入很少執行緒時,效能更好。

CountDownLatch是一種簡單的同步模式,這種模式允許執行緒在同步屏障之前做些少量的準備工作。
為了達到這種效果,在構建新的CountDownLatch例項時要給它提供一個int值(計數器)。此外,還有兩個用來控制鎖存器的方法:
countDown()和await()。前者對計數器減1,後者讓呼叫執行緒的計數器到0之前一直等到。如果計數器已經為0或更小,
則它什麼也不做。

java.util.concurrent.ConcurrentHashMap類是標準HashMap的併發版本。它改進了Collections類中提供的synchronizedMap()功能。
CopyOnWriteArrayList

Queue Java中有些多執行緒程式設計模式很大程度上都依賴於Queue實現的執行緒安全性。Queue介面被放在了java.util包中,因為即便在單執行緒程式設計中它也是一個很重要的模式,但我們的重點是多執行緒程式設計,並且假定你已經熟悉佇列的基本用法。
BlockingQueue:在向佇列中put()時,如果佇列已滿,它會讓執行緒等待佇列騰出空間。
在從佇列中take()時,如果佇列為空,會阻塞執行緒。
因為如果一個執行緒(執行緒池)的能力超過了其他執行緒,比較快的執行緒就會被強制等待,可以對整個系統起到調節作用。




相關文章