如果来自多个线程的同时调用不会创建一种情况,其中任何内存空间由一个线程写入,并且同时由另一个线程同时写入/读取,则可以将该方法视为线程安全。
这个例子显示的功能,如果所谓的多个线程可能会导致问题:
void doThreadNonsense(int input) {
this.myValue = input;
if (this.myValue > 9000) System.out.println("It's over 9000!");
}
因为这里的值是先写,然后由多个线程读取,而且是可能发生的线程A写入5 ,然后线程B写了9000,然后线程A输出的句子,因为值现在为> 9000,尽管5
随着然而只是一个小的改动输入这个功能变得线程安全:
void doThreadNonsense(int input) {
this.myValue = input;
if (input > 9000) System.out.println("It's over 9000!");
}
现在该值只能由多个线程写入,但由于在任何32位(或更高版本)机器上以原子方式写入int,因此myValue
仅由一个线程或另一个线程写入,但从不同时写入。这个例子显示了你需要仔细检查你的代码正在做什么来确定它是否是线程安全的。
如果你把它可以在静态方法 - 如上所述 - 也可以不是线程安全的:
static int myValue;
static void doThreadNonsense(int input) {
myValue = input;
if (myValue > 9000) System.out.println("It's over 9000!");
}
然而,在大多数情况下,静态函数不要在静态变量写(这还不算是干净的代码通过OOP设计模式),并且如果您不访问方法范围之外的任何内容,则代码自动是线程安全的,因为所有使用的内存位置仅在当前线程本地。
static void doThreadNonsense(int input) {
if (input> 9000) System.out.println("It's over 9000!");
}
所以你的书应该说:“遵循干净代码范例的静态方法往往是线程安全的。”
然而,这完全没有帮助,完全忽略了为什么某些东西是线程安全的,而其他东西不是。看看下面的例子,这是令人惊讶的(一些)是线程安全的,尽管它违反了许多“干净线程”的规则:
static final int[][] matrix = new int[N][M];
static void fillMatrixColumn(final int n) {
for (int m = 0; m < M; ++m) {
matrix[n][m] = calculateValue(n, m);
}
}
public static void main(String[] args)() {
IntStream.range(0, N)
.parallel()
.forEach(this::fillMatrixColumn);
printMatrix(matrix);
}
不同步,不锁定,但很多从多快乐写作线程到相同的数据结构。这仍然是线程安全的,因为在任何时候,两个线程都不会同时写入/读取同一个内存位置。
不!静态不是同步的同义词! –
如果该静态数据是可变的,则意味着每个对象都会看到更改。那是你要的吗?也许不是。 – duffymo
但是,该方法将只有一个副本,因为它是类级别变量。对? – JavaUser