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

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

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

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

由@Cybis 提供的一个答案是:

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

静态方法也是这样吗?

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

因此,我想我的最终问题是: “是否有一个定义线程安全方法的简短规则列表?如果是这样,它们是什么?”

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

122878 次浏览

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

连结: http://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html

没有硬性规定。

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

  1. 函数及其调用的所有函数必须是纯函数(没有副作用)并使用局部变量。虽然这将使您的代码线程安全,但是在。NET.
  2. 在公共对象上运行的每个函数都必须在公共对象上运行 lock。所有的锁必须按同样的顺序进行。这将使代码线程安全,但是速度会慢得难以置信,您最好不要使用多个线程。
  3. ...

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

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

在此实例中,多个线程可以并发调用 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;
}
}

您应该意识到,传递给方法的任何非 struct 或不可变的参数都可能被方法范围之外的另一个线程更改。

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

有关详细信息,请参阅 Lock 语句 C # 引用读写网 LockSlim

Lock 主要用于提供一次一个的功能,
如果您需要多个读取器和单个写入器,ReadWriterLockSlim非常有用。

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

绝对不行。你可以编写一个只有一个局部变量的程序,这个局部变量可以从一个线程访问,但不是线程安全的:

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

这也适用于静态方法吗?

绝对不行。

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

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

静态方法也是这样吗?

绝对不行。

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

也许吧。

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

你必须学会带着失望生活。这是一门很难的学科。

因此,我想我的最终问题是: “是否有一个定义线程安全方法的简短规则列表?

没有。正如您从我之前的例子中看到的 空方法可能是非线程安全的。您可能还会问“是否有一个确保方法为 正确的简短规则列表”。不,没有。线程安全不过是一种极其复杂的正确性。

此外,您提出这个问题的事实表明您对线程安全性存在根本性的误解。线程安全是程序的 全球性的属性,而不是 本地属性。之所以这么难,是因为 您必须完全了解整个程序的线程行为为了保证它的安全。

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