什么是“线程安全类型”?何时需要使用“lock”语句?

10

我已经阅读了所有有关线程安全类型和“lock”语句的文档,但仍然不完全理解。

在什么情况下需要使用“lock”语句?它与(非)线程安全类型有什么关系?谢谢。

3个回答

13

假设一个类实例中有全局变量,在其中两个线程在完全相同的时间调用该对象的方法,并且该方法对全局变量进行更新。

很可能变量中的值会被破坏。不同的语言和编译器/解释器将以不同的方式处理此问题(或根本不处理...)但重点是你会得到“不期望”的和“不可预测”的结果。

现在想象一下,方法在尝试读取或写入变量之前获得了该变量的“锁定”。第一个调用该方法的线程将在该变量上获得“锁定”,第二个调用该方法的线程将需要等待直到第一个线程释放该锁定。虽然你仍然存在竞争条件(即第二个线程可能会覆盖来自第一个线程的值),但至少你会得到可预测的结果,因为没有两个线程(彼此不知道)可以同时修改该值。

你可以使用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;
        }
    }
}

如果多个线程同时访问共享数据不会导致数据损坏,那么该类型就被认为是“线程安全”的。

请注意“不可变”和“线程安全”的区别。线程安全表示您已针对此场景编写了代码,并且在两个线程同时访问共享状态时不会发生数据损坏,而不可变性仅表示您返回一个新对象而不是修改它。 不可变对象是线程安全的,但并非所有线程安全对象都是不可变的。


1
所以如果一个类型是线程安全的,它会在内部实现锁定,我就不应该再次实现它了。对吗?谢谢Neil。 - user386167
1
是的 - 如果您正在重用其他人的类型(例如来自第三方库),并且它被宣传为“线程安全”,则不需要在其使用周围编写lock(...) { ... }语句。但是,如果您正在设置该类型的变量,并且该变量本身可能会被不同的线程修改,则需要锁定它。 - Neil Barnwell

7
线程安全的代码是指可以被多个线程访问并正常运行的代码。
在C#中,这通常需要一些同步机制。一个简单的机制是使用lock语句(背后是调用Monitor.Enter)。由lock块包围的代码块只能由一个线程访问。
任何使用不是线程安全的类型都需要您自己管理同步。
了解C#中线程的良好资源是Joe Albahari的免费电子书,可在此处找到:这里

谢谢Oded,这是一篇很棒的文章,我也强烈推荐它。 - user386167


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接