非泛型版本的 ICollection
中有 IsSynchronized
屬性和 SyncRoot
屬性,這兩個屬性被用來設計成以線程安全的方式訪問和修改集合。不過這個設計讓線程安全的訪問由集合的實現方轉嫁到了調用方,導致要麼很難實現,要麼很難調用。
雖然泛型版本的 ICollection<T>
已經改進了設計,不再引入 SyncRoot
這樣的屬性到接口中,但如果我們在某些場景下需要實現 ICollection
非泛型集合時,如何正確實現 SyncRoot 模式(SyncRoot Pattern)呢?
先上結論:
—— 不可能正確實現 SyncRoot 模式
在多線程程序設計中,爲了在保證線程安全的同時避免死鎖,不應該公開同步鎖。而 ICollection
接口中的 SyncRoot
屬性在接口中必然是公開的,於是沒有任何途徑可以保證調用方不會發生死鎖。
於是實現 SyncRoot
的正確方法應該是:
—— 避免公開 SyncRoot 屬性
所以 SyncRoot 模式應該這樣實現:
- 使用顯式接口實現,避免公開暴露此屬性
- 拋出異常,避免調用者使用此屬性
結合 .NET Core 源代碼中的一些常用寫法,我給出一個推薦的 SyncRoot 模式的寫法:
// Is this List synchronized (thread-safe)?
bool ICollection.IsSynchronized => false;
// Synchronization root for this object.
object ICollection.SyncRoot => this;
嗯,沒錯,返回了 this
,這是各種同步時絕對不應該使用的對象。然而這個屬性都是 public
了,不管返回什麼,與 this
還有什麼區別……
關於爲什麼同步時不應該返回 this
或者返回公開的對象,原因可以看我的另一篇博客:
我的博客會首發於 https://blog.walterlv.com/,而 CSDN 會從其中精選發佈,但是一旦發佈了就很少更新。
如果在博客看到有任何不懂的內容,歡迎交流。我搭建了 dotnet 職業技術學院 歡迎大家加入。
本作品採用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名呂毅(包含鏈接:https://walterlv.blog.csdn.net/),不得用於商業目的,基於本文修改後的作品務必以相同的許可發佈。如有任何疑問,請與我聯繫。