2017-06-13 81 views
2

FileManager暴露了一個write方法,其中包含一個synchronized塊,以防止併發問題:包含同步塊的實例是否需要單例?

class FileManager{ 
    Object lock = new Object(); 

    public void write() { 
     synchronized (lock) { 
      String id = nextId(); 
      write(id); 
     } 
    } 
} 

但是,如果存在的FileManager多個實例,它們的寫入方法仍然可以併發執行。將FileManager設置爲單例可以很好地解決這個可能的併發問題嗎?或者我應該以另一種方式使用syncrhonized關鍵字?

+2

如果你不想兩個'FileManager'實例能夠運行'write'同時,你可以讓它成爲一個單身人士。或者你可以讓'lock'字段靜態。然後你的'FileManager's將在同一個對象上同步。 – khelwood

+0

任何關於哪個更可取的建議? – ab11

回答

2

有幾個方法可以做到這一點:

  • 使它成爲一個單身,你也暗示,但是這是去(我不會在所有推薦的)的至少期望的方式,因爲爲了同步而讓單獨的單身人士過度殺人,而且現在沮喪的是辛格爾頓。
  • 使您鎖定對象爲靜態,即static Object lock = new Object();,這樣您將始終鎖定類級鎖定對象。
  • 使寫入方法爲靜態並同步,即public static synchronized void write() {,這樣您再次使用類級鎖對象,但區別在於此次您將使用FileManager的級別鎖,而不是您的鎖對象。

其他一些需要考慮的要點:

  • 無論你選擇的類級鎖或對象級鎖定,您將直接暴露你的鎖(類級鎖尤其如此),這基本上意味着,某些客戶端的API可以保持鎖定,並且所有依賴於對象/類級別鎖定的方法都將被阻止。例如,在類級別鎖定的情況下,您的API的某些客戶端可以執行synchronized(FileManager.class){,並且您的所有靜態+同步方法必須等到該客戶端釋放該鎖定之後,現在如果該客戶端正在進行一些密集型操作,那麼性能罰款。
  • 如果你使用一些成員變量來鎖定這樣的private static final Object lock = new Object();,那麼需要注意的一點是,使它成爲private,否則它仍會暴露你的鎖。否則,它不會受到我上面提到的問題的困擾。但是這種方法只有其他的一點 - (1)你不能在方法級使用它,你可以通過在​​塊中包含代碼塊來在方法內使用這個鎖。 (2)如果你的API的客戶想要與你正在使用這個鎖的一些同步方法同步,那麼他們不能。但是還有更深層次的東西,現在通常情況下這是鎖定發生的方式。
  • 如果您使用的是Java的最新版本,那麼可以使用像ReentrantLockReadWriteLock這樣的API,它爲鎖定提供更詳細的支持。

選擇哪種最適合您的要求。

在一般性評論,使用鎖定​​或private static final Object lock = new Object();是鎖定的老辦法,用Java提供了新的併發API,你應該使用像ReentrantLockReadWriteLock的API實現您的同步機制。

+0

如果我選擇3rd,它會鎖定所有靜態FileManager方法嗎?如果我有'公共靜態字符串read()'(不同步),執行同步'write'方法時將無法執行?如果是這樣,這看起來像是第二種選擇的輕微優勢? – ab11

+0

如果你的'read()'沒有被同步,那麼就沒有問題,但是如果你的'read()'或者其他方法是同步的並且是靜態的,那麼所有這樣的靜態和同步方法將會相互等待。只是等待我更新我的答案,提到幾個相同的評論。 – hagrawal

+0

@ ab11 - 我認爲鎖定會限制在FileManager類中的其他'synchronized'靜態方法。所以任何非'synchronized'靜態方法都不會受到影響。 –

0

是否使用單例模式取決於個別FileManager實例是否具有自己的狀態。如果所有實例基本上共享相同的狀態,那麼是的,單例模式將是一個很好的選擇。如果在另一方面,他們可以有不同的狀態,但你仍然需要跨實例方法同步訪問,那麼你可以類的靜態成員的同步操作,如:

class FileManager { 
    static final Object lock = new Object(); 
    public void write() { 
     synchronized (lock) { 
      ... 
     } 
    } 
} 
0

但是,如果存在的文件管理器的多個實例,他們的寫入方法仍然可以同時執行?

是的。它們可以並行運行,因爲鎖存在實例級別,即對象級別而不是級別級別

會使FileManager成爲一個單身人士是一個很好的解決這個可能的併發問題?

使類單身,如果它有​​塊是沒有必要的。但是如果你真的只需要你的設計的FileManager的實例,那麼你可以使用static鎖來爲Singleton。

我應該以另一種方式使用syncrhonized關鍵字嗎?

您可以使用LockReentrantLock作爲其他選擇。

請參考下面的帖子更多細節:

What does 'synchronized' mean?

Avoid synchronized(this) in Java?

Synchronization vs Lock

+0

這似乎是在衝突hagrawal的答案和我的理解。如果'lock'是一個非靜態局部變量,那麼如何調用FileManager.write()的不同實例互相阻塞? – ab11

+0

從你的問題中分散注意力。現在糾正它。 –

相關問題