
[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 保護,避免帳戶同時有兩個動作,導致款項異常。