3 回答

TA貢獻2011條經驗 獲得超2個贊
我正在嘗試從多個類中的多個方法同步對 XML 文件的讀寫操作。為此,我使用類級鎖來同步此操作。
那不是一個好主意。您應該有一個類(可能是XmlHelper)來管理 XML 文件并進行鎖定。 XmlHelper將在多個類的多個方法中使用,并將控制對文件的鎖定,而不是多個類必須擔心它。這是更好的對象設計。
也許是這樣的:
public class XmlHelper {
public XmlHelper(File xmlFile) {
public synchronized SomeObject readSomething() { ... }
public synchronized void writeSomething(SomeObject someObject) { ... }
}
然后你的Test1和Test2類必須共享同一個XmlHelper類的實例,這樣他們的鎖就會互相阻塞。實例級鎖并不總是一個好主意,因為鎖應該盡可能細粒度,但它在您的應用程序中很好,因為它是XmlHelper為多個類設計的,可以鎖定它們的 IO 操作。
Object.class使用instead of有什么影響CommonUtility.class,例如:
正如其他人所提到的,鎖定類與調用方法相同synchronized static。這種模式應該非常謹慎地使用,因為鎖的粒度太粗了。如果您的程序需要同時讀取/寫入 2 個 XML 文件怎么辦?您的類級別鎖會導致對 2 個文件的 IO 操作相互阻塞——這不是最佳的。
如果您鎖定,Object.class那么碰巧執行相同鎖定的任何其他類都會不必要地阻塞您的線程。愿上帝保佑你。
競爭條件正在受到打擊。例如:thread1 讀取文件內容并更新讀取的內容。在線程 1 寫回文件之前,線程 2 讀取內容。然后 thread1 將更新的內容寫入文件。最后 thread2 將內容寫入文件。這導致內容丟失,
有幾種方法可以做到這一點。你可以在你的類上有某種更新方法XmlHelper:
public synchronized void updateObject(...) {
SomeObjecto obj = readSomething();
// adjust object here based on the arguments
writeSomething(obj);
}
如果每個線程都需要進行自己的更新,那么它們將需要在同一個對象上進行外部鎖定。我建議鎖定XmlHelper.
synchronized (xmlHelper) {
...
}
類對象上的鎖定將起作用,但建議使用大錘子。同樣,如果您有 2 個實例XmlHelper處理 2 個不同的文件,您不希望 2 個不同文件上的 IO 操作相互阻塞。

TA貢獻1818條經驗 獲得超3個贊
我認為這兩種方法都不理想。
首先,這里建議:
您可能想知道調用靜態同步方法時會發生什么,因為靜態方法與類而不是對象相關聯。在這種情況下,線程獲取與該類關聯的 Class 對象的內部鎖。
換句話說:當您使用時,synchronized(CommonUtility.class)
您隱式地與 CommonUtility 中的所有靜態方法“同步”?synchronized
。更糟糕的是:想象一下今天的類沒有這樣的方法。但是下周,有人synchronized
在該實用程序類中添加了這樣一個靜態方法,假設只有對該方法的調用通過該監視器。最壞的情況是,這可能會導致一些丑陋的(僅限運行時)意外。
然后:尋求更廣泛的范圍(通過使用 Object.class)會使事情變得更糟。
我的回答:首先避免使用類對象。

TA貢獻1786條經驗 獲得超11個贊
IMO,“類級”鎖和“對象級”鎖的想法讓人分心。Java 中只有一種底層同步機制:synchronized (o) { ... }whereo可以是任何 Java 對象(注意在 Java 中MyClass.class 是一個對象。)
當你寫作時,
synchronized SomeType foobar(...) { ... }
這實際上只是一種使用實例作為保護其自身成員變量的鎖對象的快捷方式。
SomeType foobar(...) {
synchronized (this) {
...
}
}
所謂的“類級別”鎖定也是如此:它只是使用類本身作為保護其自身靜態成員的鎖定對象的一種簡寫方式。
說到哪...
好的做法是將鎖定對象保持在它保護的數據附近(對于“附近”的某些定義)。如果數據是private,那么鎖定對象應該是private。如果數據是某個實例的成員,那么鎖對象應該是同一實例的成員,等等。
Object.class不是特別“接近”任何東西。它可以像任何其他對象一樣工作,但是使用它會使您的代碼更難理解,因為讀者會花時間想知道是什么促使您選擇它Object.class,并想知道您的選擇是否基于誤解。
我自己的偏好,為了保護實例成員,看起來像這樣:
class MyClass {
private final Object lock = new Object();
private SomeType someVariableThatNeedsProtection = ...;
private SomeOtherType someOtherVariableThatAlsoNeedsProtection...;
...
public ... foobar(...) {
synchronized(lock) {
...
}
}
}
而且,如果我需要保護static成員:
...
private static final Object lock = new Object();
...
變量lock是private,就像它保護的數據一樣。想要了解您的代碼的任何人都不需要花費任何時間來搜索受同一鎖對象保護的任何其他內容,因為他們知道無法從方法外部訪問這些內容MyClass。
變量lock也是final。這將使讀者不必檢查您的代碼以確保它始終是用作鎖的同一對象。(提示:如果你認為你需要能夠分配lock變量,那么你要么在做一些超出許多程序員舒適水平的復雜事情,要么你正在犯一個嚴重的錯誤。)
添加回答
舉報