Java Concurrency #2: 什麼是鎖 — Lock

Charlie Lee
Bucketing
Published in
4 min readJul 6, 2020

如果要嘗試Concurrency提升專案產品的效率,有甚麼是首先需要知道的呢

Photo by Jose Fontano on Unsplash

文章項目

  • 什麼是鎖 - Lock
  • Synchronized
  • 粗細鎖

什麼是鎖 - Lock

如上一篇文章所述,在Concurrency時因為CPU會不斷切換Thread導致執行時的原子性問題,而CPU Cache又會導致資源可見性問題,這時就會需要有一個方法讓CPU在處理有可見性問題資料時,只能有一個Thread可以執行,這就是Lock 鎖。

最直觀鎖的模型如下圖:

在開發Concurrency時,需要對有可見性問題區域(Critical Section)做鎖的保護,確保Thread運行到此Section時,只會有一個執行。但上面的基礎鎖模型會有一個很大的問題,鎖住的區域會過大,換言之只能單執行緒執行的範圍過大,這也代表Concurrency的優勢不再存在,所以延伸到了進階的鎖模型。

進階的鎖模型:

進階鎖的模型,明確定義了資源與鎖的關係,不再單純鎖住有可見性和原子性的區塊,而是細節的鎖住有可見性問題的資源。

Synchronzied

Synchronzied是Java提供最基礎的鎖類型,只需要在需要鎖的行為方法或是區塊前面加上Synchronized前綴字,就可以幫助開發者達到最基礎的Lock 鎖。

如下範例,加上Synchronied之後就解決了Race Condition問題。

看完之後,可能會對於Synchronied有很大的疑問,他並不符合開頭說的lock模型。因為Java JVM已經幫開發者處理好這問題了,如果lock後忘記unlock會造成應用程式整個死鎖,JVM為了友善對待每一位開發者就預先處理了這問題,讓開發者只要專注在大括弧區塊的邏輯就好,所以Synchronied也是最基礎的Concurrency lock應用。

Class lock / Object lock

上面的範例是靜態鎖(Class lock),這類型的lock會黏著在每個Class中,這樣也變相造成了,有些lock只要跟著Object就好,如果使用了Class lock就會造成每個Object在處理自己的資料時,也會被其他Object影像跟著排隊等待lock的釋放。所以就會需要有Object lock的出現,如下:

從上面的範例可以觀察到,就算使用了Object lock也可以保證資料的一致性,但是在呼叫方法時不用再等待其他Object釋放Class lock資源

  • 在此範例的this鎖的是當下的Object,如果有其他需求可以特別創造一個Obejct放入Synchronized之中,做更細節的操作

鎖的顆粒 / Rough lock & fine lock

上面所講的Lock都是Rough lock,意味著Lock鎖住的範圍比較大(Class Lock是最粗的鎖),如果鎖住的範圍過大,也會造成上面提到Class/Object Lock的問題,Concurrency的優勢不再存在(每個Thread都需要等待,那又如同同步了),那如何將鎖解離呢,可以看下面的例子:

上方的Account範例,是負責ATM匯款領錢更改密碼的邏輯物件,在這範例我們將和餘額有關的操作與和更改密碼的操作解離了,兩個行為都有各自的物件鎖,如果在大流量下操作餘額而且Database回應緩慢的話,也不會影響到要更改密碼的使用者,還可以保持Conurrency的高效能力

總結

今天介紹了什麼是鎖 - lock,以及如何使用Synchronized實作一個鎖,在文章後段,我們透過了一個Account匯款和改密碼的粒子,將原本顆粒度較粗的鎖解離成兩個細粒度的鎖

下回預告: 下回會介紹甚麼是死鎖,以及如何避免和預防死鎖情形。

如果讀者們對Java Concurrency有興趣的話歡迎閱讀,如果有其他想法也歡迎留言攻擊我

--

--