爲什麼實現 .NET 的 ICollection 集合時需要實現 SyncRoot 屬性?如何正確實現這個屬性?

非泛型版本的 ICollection 中有 IsSynchronized 屬性和 SyncRoot 屬性,這兩個屬性被用來設計成以線程安全的方式訪問和修改集合。不過這個設計讓線程安全的訪問由集合的實現方轉嫁到了調用方,導致要麼很難實現,要麼很難調用。

雖然泛型版本的 ICollection<T> 已經改進了設計,不再引入 SyncRoot 這樣的屬性到接口中,但如果我們在某些場景下需要實現 ICollection 非泛型集合時,如何正確實現 SyncRoot 模式(SyncRoot Pattern)呢?


先上結論:

—— 不可能正確實現 SyncRoot 模式

在多線程程序設計中,爲了在保證線程安全的同時避免死鎖,不應該公開同步鎖。而 ICollection 接口中的 SyncRoot 屬性在接口中必然是公開的,於是沒有任何途徑可以保證調用方不會發生死鎖。

於是實現 SyncRoot 的正確方法應該是:

—— 避免公開 SyncRoot 屬性

所以 SyncRoot 模式應該這樣實現:

  1. 使用顯式接口實現,避免公開暴露此屬性
  2. 拋出異常,避免調用者使用此屬性

結合 .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/),不得用於商業目的,基於本文修改後的作品務必以相同的許可發佈。如有任何疑問,請與我聯繫

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章