我经常看到这个:
object lockObj;
List<string> myStrs;
// ...
lock(lockObj)
{
myStrs.Add("hello world");
}
为什么要有单独的对象?当然你可以这样做:
List<string> myStrs;
// ...
lock(myStrs)
{
myStrs.Add("hello world");
}
我经常看到这个:
object lockObj;
List<string> myStrs;
// ...
lock(lockObj)
{
myStrs.Add("hello world");
}
为什么要有单独的对象?当然你可以这样做:
List<string> myStrs;
// ...
lock(myStrs)
{
myStrs.Add("hello world");
}
仅当myStrs
是 public 时直接在列表上锁定是一个问题,因此也可以被其他调用者锁定,从而导致可能的死锁。
如果是私人成员,那应该没有问题,但无论如何锁定一个单独的成员object
是一个好习惯。
请参阅此类似问题以获得更详细的答案: 为什么 lock(this) {...} bad?
通常,避免锁定公共类型或超出代码控制范围的实例。常见的构造 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反了此准则:
- 如果实例可以公开访问,lock (this) 是一个问题。
- 如果 MyType 可公开访问,则 lock (typeof (MyType)) 是一个问题。
- lock(“myLock”) 是一个问题,因为进程中使用相同字符串的任何其他代码都将共享相同的锁。
最佳实践是定义一个私有对象来锁定,或者一个私有静态对象变量来保护所有实例共有的数据。
形成文档锁 c#
您的字符串列表是用于内部实现细节的列表。
如果您更改实现以重新初始化字符串列表的方式,则第二个版本的问题可能会上升。
那么你的实现的线程安全性可能会被破坏。
因此,最好使用单独的对象进行同步并将该对象声明为只读。
这个想法是始终锁定只能由我们正在查看的代码访问的私有成员。而当我们锁定我们无法控制的成员(如公共成员或类似成员)时,很可能代码的其他部分已经可以锁定。这可能会导致意外的阻塞行为。
所以,我认为这导致了经验法则/拥有私有对象的最佳实践,特别是用于锁定。
我很想看看是否还有更多原因。
如果将列表用作锁定对象,并将其重置为null,则 lock(myStringList) 将引发 ArgumentNullException。下面是控制台应用程序的简单测试代码。
private static IList<string> mystringList = new List<string>();
static void Main(string[] args)
{
new Thread(() =>
{
try
{
while (true)
{
//Acquire the lock
lock (mystringList)
{
//Do something with the data
Thread.Sleep(100);
Console.WriteLine("Lock acquired");
}
}
}
catch (Exception exception)
{
Console.WriteLine("Exception: " +exception.Message);
}
}).Start();
new Thread(() =>
{
//Suppose we do something
Thread.Sleep(1000);
//And by some how reset the list to null
mystringList = null;
}).Start();
Console.ReadLine();
}