Udemy Course Multithreading, Concurrency & Performance 15

Critical Section & Synchronization

ZONGRU Li
Jul 26, 2021

由前一節最後可知

一般來說我們在一堆的運算過程中,希望保持atomic operation

依序完成三個運算,而不是三個運算同時運行

所以我們要確保同一時間只有only 1的thread進到這個aggregateFunction內!

理想上如下:

當Thread A進去開始運算後,就好像前後上了鎖,防止其他Thread在進去
此時Thread B進不來
直到Thread A離開了,Thread B才能進去運算

而Java針對這個理想有一個keyword:synchronized

當都有synchronized修飾字時,同一時間僅能一個thread進到內部

上圖可參考stackoverflow解說

或參考以下自己嘗試的code:

上述code執行後會看到:

一進入sayHelloForA,則Thread B就進不去sayHelloForB

另外

回到前節的問題

問題就在於這兩個method沒有synchronized

在此複製一樣的code放到不同package內並改寫為以下

為了避免取值發生依樣問題,在getItems也加入synchronized修飾字

再次執行得到:

完整code如下:

更有效率的synchronized關鍵字使用方式是如下

創建lock物件來當作synchronized的鎖

synchronized修飾字不放在Method前,而是在Method內部使用

盡量的減小critical section的範圍

這個好處是不用將整個包含Method都變成synchronized

實際運作演練如下

改寫後為Main2.java

再次執行得到:

依樣結果,但是這個寫法會更有效率

如上假設有Thread A進到item++的運算中,由以上寫法

則下一個Thread B至少可以進到increment method內

但是要進到item++運算邏輯則需要排隊等候Thread A跑完

也就是說當increment method內有更多複雜邏輯的時候

只針對critical section部分做lock就好,而不是無腦的將整個method做lock

效率才高!

特別注意-->這裡可將synchronized block稱為Reentrant(可重入)

亦即Thread A已經進入到synchronized method 1

但同時Thread A也還是能進入到synchronized method 2

結論

1.簡單方式就是在Method前加入synchronized

2.或是用Object的方式使用synchronized,但是code會變比較冗長

其他鎖定關鍵邏輯僅供單一Thread進入的還有java5時代有的BlockingQueue

BlockingQueue可參考這個github範例

參考課程

--

--

ZONGRU Li
ZONGRU Li

Written by ZONGRU Li

2022/11/17 開源部分個人筆記給LINE "Java程式語言討論區"社群,希望能對社群的技術學習做一點點貢獻.(掩面....記得退訂閱!

No responses yet