@Synchronized
synchronized
的正確用法:不要暴露你的鎖。
概觀
@Synchronized
是 synchronized
方法修飾詞的更安全變體。 就像 synchronized
一樣,此註解只能用於靜態方法和實例方法。 它的運作方式與 synchronized
關鍵字類似,但它鎖定不同的物件。 關鍵字鎖定 this
,但註解鎖定名為 $lock
的私有欄位。
如果該欄位不存在,則會為您建立。 如果您註解 static
方法,則註解會鎖定名為 $LOCK
的靜態欄位。
如果您願意,您可以自行建立這些鎖。 如果您已自行建立 $lock
和 $LOCK
欄位,則當然不會產生這些欄位。 您也可以選擇鎖定另一個欄位,方法是將其指定為 @Synchronized
註解的參數。 在此用法變體中,欄位將不會自動建立,您必須明確地自行建立它們,否則會發出錯誤。
鎖定 this
或您自己的類別物件可能會產生不幸的副作用,因為其他不受您控制的程式碼也可能鎖定這些物件,這可能會導致競爭條件和其他討厭的執行緒相關錯誤。
如果您偏好 java.util.concurrent.locks
樣式的鎖(如果您使用虛擬執行緒,則建議使用),請查看 @Locked
。
使用 Lombok
import lombok.Synchronized;
|
原始 Java
public class SynchronizedExample {
|
支援的設定鍵
-
lombok.synchronized.flagUsage
= [warning
|error
] (預設值:未設定) - 如果已設定,Lombok 會將任何
@Synchronized
的使用標記為警告或錯誤。
小字
如果 $lock
和/或 $LOCK
是自動產生的,則欄位會使用空的 Object[]
陣列初始化,而不是像大多數顯示此模式的程式碼片段所使用的 new Object()
。 Lombok 這樣做是因為新的物件是 *不可* 序列化的,但 0 大小的陣列是。 因此,使用 @Synchronized
不會阻止您的物件被序列化。
在您的類別中至少有一個 @Synchronized
方法意味著將會有一個鎖定欄位,但如果您稍後移除所有此類方法,將不再有鎖定欄位。 這意味著您預定的 serialVersionUID
會變更。 如果您打算透過 Java 的序列化機制長期儲存類別,我們建議您*始終*將 serialVersionUID
新增至您的類別。 如果您這樣做,從您的方法中移除所有 @Synchronized
註解將不會破壞序列化。
如果您想知道為什麼當您為鎖定物件選擇自己的名稱時,欄位不會自動產生:因為否則在欄位名稱中輸入錯誤將導致一個*非常*難以找到的錯誤!