在Java中发生的事先机制
作者:互联网
我在Java中遇到过关于先发生机制的问题.这是一个例子:
public class MyThread extends Thread {
int a = 0;
volatile int b = 0;
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
read();
}
public void write(int a, int b) {
this.a = a;
this.b = b;
}
public void read() {
System.out.println(a + " " + b);
}
}
这是事先发生的明显例子,这是足够安全的,正如我所知道的那样. a将正确获得新值,因为它在b初始化之前.但重新排序是否意味着安全性得不到保证?我在说这个:
public void write(int a, int b) {
this.b = b;
this.a = a;//might not work? isn't it?
}
UPD主线程:
public class Main {
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
t.start();
t.write(1, 2);
}
}
解决方法:
使b变为volatile并且在将值设置为a后将写入值设置为b可保证:
>如果在a之前读取b,那么
> a的值不会超过之前写入b时的值.
即,对b的写入和对b的读取充当同步点或栅栏,这意味着在从b读取之后写入的任何内容将在从b读取之后可读(如果a被写入多于一次) ,以下写入可能会或可能不会显示).
但是,您的代码现在不安全.在阅读中,您有以下表达式:
a + " " + b
在Java中,expressions are evaluated left-to-right.这意味着,将在b之前评估a.因此,读取a将完全有可能看到a的旧值,而b的读取将看到b的新值.如果你在a之前读过b,那么b的写入和读取之间的发生之前的关系将涵盖对a的写入和对a的读取.现在,它没有.
至于写入中的重新排序操作 – 这将明显消除b的排序保证对a的操作的影响,即使读取首先读取b然后读取a.
为了可视化事物,只给出b是易变的:
当前代码不保证在 – 的操作顺序 –
write a read a
write b --> happens before --> read b
使用给定读取重新排序写入也不会顺序 –
read a
write b --> happens before --> read b
write a
即使给定的读取是固定的,也不会按顺序排序 –
write b --> happens before --> read b
write a read a
唯一安全的做法是保持当前写入并修复读取 –
write a
write b --> happens before --> read b
read a
标签:java,multithreading,volatile,java-memory-model 来源: https://codeday.me/bug/20190624/1277803.html