这是JLS中关于JMM关系之前发生的事情(第17.4.5节):
应当指出的是,在两项行动之间的关系发生之前就出现了一种情况,并不一定意味着它们必须在执行中按这种顺序进行。
我对这一发言的例子感兴趣。
我是否理解这一点,例如:
Thread 1
x = 1
lock M
y = 2
unlock M ----------------------->Thread 2:
lock M
z = 3
w = 4
unlock M显然,在此执行跟踪中,在(x = 1)和(w =4)之间的关系发生之前:
(x = 1) happens-before (w = 4)在这种情况下,(x = 1)被排序为(w = 4)在执行跟踪中。
Thread 1不使用变量w。因此,我们可以将它放在(x = 1)之前,而不违背Thread 1和Thread 2的逻辑。
这是否意味着如果我们重新排序(x = 1)和(w = 4),那么就会发生-在这些语句之间的关系保持之前?
如果你有一些其他的例子,请提供。
发布于 2016-01-14 09:58:39
是的,你是对的,在独立数据发生变化之前,关系就会发生。至于其他的例子,不要忘记,在同样线程中的事件之前也会发生这种情况。规则非常简单:
如果x和y是同一个线程的动作,x以程序顺序出现在y之前,则hb(x,y)。
因此,Java方法中的每条语句都会发生--在后面的每条语句之前,但是当然,JIT编译器和CPU可以自由地重新排序独立的语句(他们实际上经常这样做以优化性能)。有时,您可以从另一个没有发生的线程中观察到这种重新排序--在与当前线程的关系之前。
发布于 2016-01-14 09:59:56
线程1不使用变量w。
您不能假设这是一个原因,因为实际上,Java模型没有考虑在线程隔离上下文()中重新排序指令是否安全。
在没有锁定或内存障碍的情况下,JMM只保证在同一线程中的语句之前发生。
在您的情况下,您对同一个对象(M)有一个锁定机制,因此“发生-之前”发生。
Java中的synchronized (锁)或其他原子变量处理内存屏障、和原子性。关于信息,构造函数中的volatile变量和final变量分配只处理内存障碍。
以这个示例为例,它完全没有内存障碍:
Class Reordering {
int x = 0, y = 0;
public void writer() {
x = 1;
y = 2;
}
public void reader() {
int r1 = y;
int r2 = x;
}
} 假设这段代码是在两个线程中并发执行的,并且y的读看到值2。因为这个写是在写到x之后,所以程序员可能会假设x的读必须看到值1。然而,写可能已经被重新排序了。如果发生这种情况,那么对y的写入就会发生,两个变量的读取都会随之进行,然后对x的写入就会发生。结果是r1的值为2,而r2的值为0。
https://stackoverflow.com/questions/34775517
复制相似问题