可以锁定System.Collections.Generic.List <t>吗?

Kar*_*rim 10 c#

我一直在阅读有关syncroot元素但我无法在List类型中找到它.那么应该如何使用System.Collections.Generic.List <>类型完成多线程同步?

Win*_*ith 11

为什么要锁定List<T>而不是列表的特定实例?

通常建议锁定的最佳方法是锁定仅为此目的而创建的私有对象.

private readonly object myListLock = new object();

// Everywhere you access myList
lock(myListLock)
{
 // do stuff with myList
}
Run Code Online (Sandbox Code Playgroud)

有关C#中线程的精彩指南,请参阅Joe Albahari撰写的这本免费电子书(C#中的线程).

  • 为什么这比锁定列表实例更好? (2认同)
  • 关于:为什么这比锁定列表实例更好? - 如果锁定到列表的实例"lock(myList)",则执行类似"myList = new List <T>"的操作时使用锁定.锁定将是旧实例. (2认同)

Nad*_*zie 11

你无法找到它的原因是因为它被明确删除了.如果它确实是您想要做的,请使用SynchronizedCollection<T>或创建专用的同步对象.最好的方法(一般)是创建一个专用的同步对象,如Winston所示.

SyncRoot属性的基本问题是它提供了一种错误的安全感 - 它只处理一组非常狭窄的情况.假设锁定SyncRoot足够好,开发人员通常会忽略整个逻辑操作的同步.

您通常希望避免锁定类型(List<T>在本例中).例如,如果您有两个类型的实例,或者另一个类型也使用锁定List<T>,那么它们都将竞争单个全局锁定.实际上,您要实现的是单个对象的正确同步.


Mat*_*vis 7

您必须将通用列表转换为ICollection如下所示:

using System.Collection; // required for ICollection
using System.Collection.Generic;
List<int> myIntList = new List<int>();
lock (((ICollection)myIntList).SyncRoot)
{
    // do your synchronized stuff here...
}
Run Code Online (Sandbox Code Playgroud)

请记住,这只会同步访问通用列表的元素.它并没有同步访问泛型列表变量,例如myIntList.如果myIntList在某个时候用新列表替换,则使用SyncRoot是不够的.在这种情况下,我建议创建一个可用于两种同步方案的特定同步对象.