3 回答

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

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

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