我已经阅读了所有有关线程安全类型和“lock”语句的文档,但仍然不完全理解。
在什么情况下需要使用“lock”语句?它与(非)线程安全类型有什么关系?谢谢。
假设一个类实例中有全局变量,在其中两个线程在完全相同的时间调用该对象的方法,并且该方法对全局变量进行更新。
很可能变量中的值会被破坏。不同的语言和编译器/解释器将以不同的方式处理此问题(或根本不处理...)但重点是你会得到“不期望”的和“不可预测”的结果。
现在想象一下,方法在尝试读取或写入变量之前获得了该变量的“锁定”。第一个调用该方法的线程将在该变量上获得“锁定”,第二个调用该方法的线程将需要等待直到第一个线程释放该锁定。虽然你仍然存在竞争条件(即第二个线程可能会覆盖来自第一个线程的值),但至少你会得到可预测的结果,因为没有两个线程(彼此不知道)可以同时修改该值。
你可以使用lock
语句获得变量的锁定。通常,你会定义一个单独的对象变量,并将其用于锁定对象:
public class MyThreadSafeClass
{
private readonly object lockObject = new object();
private string mySharedString;
public void ThreadSafeMethod(string newValue)
{
lock (lockObject)
{
// Once one thread has got inside this lock statement, any others will have to wait outside for their turn...
mySharedString = newValue;
}
}
}
如果多个线程同时访问共享数据不会导致数据损坏,那么该类型就被认为是“线程安全”的。
请注意“不可变”和“线程安全”的区别。线程安全表示您已针对此场景编写了代码,并且在两个线程同时访问共享状态时不会发生数据损坏,而不可变性仅表示您返回一个新对象而不是修改它。 不可变对象是线程安全的,但并非所有线程安全对象都是不可变的。
lock
语句(背后是调用Monitor.Enter
)。由lock
块包围的代码块只能由一个线程访问。
lock(...) { ... }
语句。但是,如果您正在设置该类型的变量,并且该变量本身可能会被不同的线程修改,则需要锁定它。 - Neil Barnwell