为了回答您的问题(正如其他人已经提出的那样),您提供的代码示例存在一些潜在问题:
private static string mutex= "ABC";
- 变量
mutex 不是不可变的。
- 字符串文字
"ABC" 将在您的应用程序的任何地方引用相同的内部对象引用。
一般来说,我建议不要锁定字符串。但是,我遇到了一个有用的案例。
在某些情况下,我维护了一个锁定对象字典,其中的键是我所拥有的某些数据的独特之处。这是一个人为的例子:
void Main()
{
var a = new SomeEntity{ Id = 1 };
var b = new SomeEntity{ Id = 2 };
Task.Run(() => DoSomething(a));
Task.Run(() => DoSomething(a));
Task.Run(() => DoSomething(b));
Task.Run(() => DoSomething(b));
}
ConcurrentDictionary<int, object> _locks = new ConcurrentDictionary<int, object>();
void DoSomething(SomeEntity entity)
{
var mutex = _locks.GetOrAdd(entity.Id, id => new object());
lock(mutex)
{
Console.WriteLine("Inside {0}", entity.Id);
// do some work
}
}
这样的代码的目标是在实体的Id 的上下文中序列化DoSomething() 的并发调用。缺点是字典。实体越多,它就越大。这也是需要阅读和思考的更多代码。
我认为 .NET 的字符串实习可以简化事情:
void Main()
{
var a = new SomeEntity{ Id = 1 };
var b = new SomeEntity{ Id = 2 };
Task.Run(() => DoSomething(a));
Task.Run(() => DoSomething(a));
Task.Run(() => DoSomething(b));
Task.Run(() => DoSomething(b));
}
void DoSomething(SomeEntity entity)
{
lock(string.Intern("dee9e550-50b5-41ae-af70-f03797ff2a5d:" + entity.Id))
{
Console.WriteLine("Inside {0}", entity.Id);
// do some work
}
}
这里的区别是我依靠字符串实习来为每个实体 ID 提供相同的对象引用。这简化了我的代码,因为我不必维护互斥体实例的字典。
请注意我用作命名空间的硬编码 UUID 字符串。如果我选择在我的应用程序的另一个区域采用相同的方法锁定字符串,这一点很重要。
根据情况和开发人员对细节的关注程度,锁定字符串可能是个好主意或坏主意。