首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >是什么让方法成为线程安全的?规则是什么?

是什么让方法成为线程安全的?规则是什么?
EN

Stack Overflow用户
提问于 2012-03-24 08:28:03
回答 4查看 116.5K关注 0票数 172

对于是什么让一个方法是线程安全的,有没有总体的规则/指南?我知道可能有一百万种一次性的情况,但是一般情况下呢?有这么简单吗?

  1. 如果一个方法只访问局部变量,那么它是线程安全的。

是这样吗?这也适用于静态方法吗?

@Cybis提供的一个答案是:

局部变量不能在线程之间共享,因为每个线程都有自己的堆栈。

静态方法也是这样吗?

如果一个方法被传递了一个引用对象,这会破坏线程安全吗?我做了一些研究,有很多关于某些情况的研究,但我希望能够通过使用一些规则来定义指导原则,以确保一个方法是线程安全的。

所以,我想我的终极问题是:“是否有定义线程安全方法的规则的简短列表?如果有,它们是什么?”

编辑

这里提出了很多好的观点。我认为这个问题的真正答案是:“没有简单的规则来确保线程安全。”凉爽的。很好。但总的来说,我认为公认的答案提供了一个很好的,简短的总结。总是有例外的。那就这样吧。我可以接受这个事实。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-03-24 08:44:47

如果一个方法(实例或静态)只引用该方法范围内的变量,那么它是线程安全的,因为每个线程都有自己的堆栈:

在这种情况下,多个线程可以同时调用ThreadSafeMethod,而不会出现问题。

代码语言:javascript
复制
public class Thing
{
    public int ThreadSafeMethod(string parameter1)
    {
        int number; // each thread will have its own variable for number.
        number = parameter1.Length;
        return number;
    }
}

如果该方法调用其他仅引用局部作用域变量的类方法,也是如此:

代码语言:javascript
复制
public class Thing
{
    public int ThreadSafeMethod(string parameter1)
    {
        int number;
        number = this.GetLength(parameter1);
        return number;
    }

    private int GetLength(string value)
    {
        int length = value.Length;
        return length;
    }
}

如果一个方法访问任何(对象状态)属性或字段(实例或静态),那么您需要使用锁来确保值不会被其他线程修改:

代码语言:javascript
复制
public class Thing
{
    private string someValue; // all threads will read and write to this same field value

    public int NonThreadSafeMethod(string parameter1)
    {
        this.someValue = parameter1;

        int number;

        // Since access to someValue is not synchronised by the class, a separate thread
        // could have changed its value between this thread setting its value at the start 
        // of the method and this line reading its value.
        number = this.someValue.Length;
        return number;
    }
}

您应该知道,传递给该方法的任何既不是结构参数也不是不可变参数的参数可能会被该方法作用域之外的另一个线程改变。

为了确保适当的并发性,您需要使用锁定。

有关详细信息,请参阅lock statement C# referenceReadWriterLockSlim

lock主要用于提供一次一个的功能,

如果您需要多个读取器和单个写入器,则ReadWriterLockSlim非常有用。

票数 150
EN

Stack Overflow用户

发布于 2012-03-24 14:32:11

如果一个方法只访问局部变量,那么它是线程安全的。是这样吗?

绝对不是。您可以只使用从单个线程访问的单个局部变量来编写程序,但该线程不是threadsafe:

https://stackoverflow.com/a/8883117/88656

这也适用于静态方法吗?

绝对不是。

由@Cybis提供的一个答案是:“局部变量不能在线程之间共享,因为每个线程都有自己的堆栈。”

绝对不是。局部变量的显著特征是它只在局部作用域中可见,而不是分配在临时池中。从两个不同的线程访问同一个局部变量是完全合法的,也是可能的。你可以通过使用匿名方法、lambda、迭代器块或异步方法来实现。

对于静态方法也是这样吗?

绝对不是。

如果一个方法被传递了一个引用对象,会破坏线程安全吗?

也许吧。

我做了一些研究,有很多关于某些情况的研究,但我希望能够通过使用一些规则来定义指导原则,以确保一个方法是线程安全的。

你必须学会在失望中生活。这是一个非常困难的问题。

所以,我想我的终极问题是:“是否有定义线程安全方法的简短规则列表?”

不是的。正如您在前面的示例中看到的,空方法可以是非线程安全的。你也可以问“有没有一个简短的规则列表来确保一个方法是正确的”。不,没有。线程安全只不过是一种极其复杂的正确性。

此外,您提出这个问题的事实表明您对线程安全的根本误解。线程安全是程序的全局属性,而不是局部属性。之所以很难做到正确,是因为你必须对整个程序的线程行为有一个完整的了解,以确保它的安全性。

再看看我的例子:每个方法都是微不足道的。正是这些方法在“全局”级别上相互交互的方式导致了程序死锁。你不能看着每个方法,然后把它作为“安全”,然后期望整个程序是安全的,就像你不能得出结论,因为你的房子是100%非中空的砖块,所以房子也不是中空的。房屋的空洞性是整个事物的整体属性,而不是其各个部分的属性的集合。

票数 116
EN

Stack Overflow用户

发布于 2012-03-24 08:39:41

没有硬性规定。

下面是在.NET中确保代码线程安全的一些规则,以及为什么这些规则不是好规则:

  1. 函数及其调用的所有函数必须是纯函数(无副作用)并使用局部变量。
  2. 每个在公共对象上操作的函数都必须在公共对象上执行lock。所有的锁必须以相同的顺序完成。这将使代码线程安全,但它将非常慢,并且您最好不要使用多个threads.
  3. ...

没有使代码线程安全的规则,你唯一能做的就是确保你的代码无论被执行多少次都能正常工作,每个线程都可以在任何时候被中断,每个线程都处于自己的状态/位置,这对于每个访问公共对象的函数(静态的或其他的)来说都是如此。

票数 13
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9848067

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档