是什么使方法线程安全?规则是什么

本文关键字:是什么 规则 安全 线程 方法 | 更新日期: 2023-09-27 18:28:55

是否有使方法线程安全的总体规则/指南?我知道可能有一百万种一次性情况,但总的来说呢?就这么简单吗?

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

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

@Cybis提供的一个答案是:

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

静态方法也是这样吗?

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

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

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

是什么使方法线程安全?规则是什么

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

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

public class Thing
{
    public int ThreadSafeMethod(string parameter1)
    {
        int number; // each thread will have its own variable for number.
        number = parameter1.Length;
        return number;
    }
}

如果该方法调用仅引用本地范围变量的其他类方法,也是如此:

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;
    }
}

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

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;
    }
}

您应该知道,传递给方法的任何不是结构或不可变的参数都可能被方法范围外的另一个线程突变。

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

有关详细信息,请参阅锁定语句C#引用和ReadWriterLockSlim。

lock主要用于提供一次一个的功能,
如果您需要多个读者和单个作者,ReadWriterLockSlim非常有用。

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

绝对不是。您可以编写一个程序,其中只有一个本地变量可以从一个线程访问,但这不是线程安全的:

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

这也适用于静态方法吗?

绝对不是。

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

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

静态方法也是这样吗?

绝对不是。

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

也许吧。

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

你必须学会在失望中生活。这是一个很难的题目。

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

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

此外,您提出这个问题表明您对线程安全性存在根本误解。线程安全是程序的全局属性,而不是本地特性。之所以很难做到正确,是因为您必须完全了解整个程序的线程行为,才能确保其安全性。

再次看一下我的例子:每个方法都是琐碎的。正是这些方法在"全局"级别上相互交互的方式导致了程序死锁。你不可能看每一种方法都认为它是"安全的",然后期望整个程序是安全的,就像你可以得出结论,因为你的房子是由100%非空心砖制成的,所以房子也是非空心的一样。房子的空洞是整个事物的整体特性,而不是其各部分特性的总和。

没有硬性规定。

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

  1. 函数及其调用的所有函数必须是纯函数(没有副作用),并使用局部变量。尽管这将使您的代码线程安全,但在.NET中使用此限制也可以做一些有趣的事情
  2. 每个对公共对象进行操作的函数都必须对公共对象执行lock。所有锁都必须按相同的顺序进行。这将使代码线程安全,但速度会非常慢,而且您最好不要使用多个线程

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

它必须使用对象锁、无状态或不可变进行同步。

链接:http://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html