[Java] Synchronized 的四種用法,讀懂這篇就夠了

[Java] Synchronized 的四種用法,讀懂這篇就夠了

最近寫 Java 程式遇到各個 Thread 之間共用資料保護的問題,做了點功課後理解 Synchronized 的用法,寫下筆記以免忘記。

Synchronized 簡單介紹

Synchronized 使用時,需指定一個物件,系統會 Lock 此物件,當程式進入 Synchronized 區塊或 Method 時,該物件會被 Lock,直到離開 Synchronized 區塊時才會被釋放。

在 Lock 期間,鎖定同一物件的其他 Synchronized 區塊,會因為無法取得物件的 Lock 而等待。

待 Synchronized 區塊執行完釋放 Lock 後,其他鎖定同一物件的 Synchronized 區塊中,Java 會讓其中一個區塊取得該鎖定物件的 Lock 而可以執行。

其他鎖定同一物件的 Synchronized 區塊就繼續等。

Synchronized 的各種用法

1. Synchronized Method

synchronized public void syncMethod() {

}

此種 synchronized 用法鎖定的物件為 Method 所屬的物件 Instance,只要物件被 new 出超過一個以上的 Instance,就有可能保護不到 Method 內程式。

但如果此物件只會被 new 出一個 Instance,譬如 new 出來後就放到 ServletContext,要用的時候從 ServletContext 中拿出來執行,就可以避免此情況。

2. Synchronized Static Method

synchronized static public void syncMethod() {

}

此種 synchronized 用法鎖定的物件為 Method 所屬的物件的 Class,不管被 new 出幾個的 Instance,都能夠保證同一個時間只會有一個 Thread 在執行此 Method。

3. Synchronized(this)

public void syncMethod() {
synchronized(this) {

}
}

此種 synchronized 用法與 synchronized method 用法一樣,都是鎖定 Method 所屬的物件本身。

4. Synchronized(SomeObject)

public void syncMethod() {
synchronized(SomeObject) {

}
}

此種 synchronized 用法鎖定的是 SomeObject,如果 SomeObject 是兩個不同 Instance,那 synchronized 區塊內就有可能被同時執行。

如果每一個 Synchronized 的 SomeObject 都是同一個 Instance (或者 SomeObject 本身就是 Static),就可以保證區塊內同時間只會被一個 Thread 執行。

當使用 Synchronized (SomeObject) 時,SomeObject 本身處於被 Lock 狀態,但此時 SomeObject 內的值是可以被更改的,Lock 只是同步化的狀態,跟物件本身的資料無關,不代表不能更改資料。

使用時機

Synchronized 的使用時機很難定義,比較常見的情況是,當程式中會取出某一個共用的物件且會判斷物件內容值,再更新物件內容時,此情況大部分都需要 synchronized 保護。

例如到 ATM 提款機提款時,要先取出用戶的帳戶餘額,扣除提款的金額,再更新回去。此時就要 synchronized 保護,避免帳戶同時有兩個動作,導致款項異常。