重新排序JMM之前发生的关系

时间:2016-01-13 19:35:41

标签: java concurrency jls java-memory-model

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 1Thread 2的逻辑。

这是否意味着如果我们重新排序(x = 1)和(w = 4)然后发生 - 在这些语句之间的关系保留之前?

如果您有其他一些例子,请提供。

2 个答案:

答案 0 :(得分:1)

是的,你是对的,发生在 - 当独立数据发生变化时,关系成立之前。至于其他示例,请不要忘记发生之前 - 也适用于同一线程中的事件。规则很简单:

  

如果 x y 是同一个线程的操作, x 按照程序顺序出现在 y 之前,然后 hb(x,y)

因此,Java方法中的每个语句都会在每个后续语句之前发生,但当然JIT编译器和CPU可以自由地重新排序独立语句(并且它们实际上经常这样做以优化性能)。有时你可以从另一个没有发生过的线程中观察这个重新排序 - 在与当前线程的关系之前。

答案 1 :(得分:1)

  

线程1不使用变量w

您不能认为这是一个原因,因为实际上,Java内存模型没有考虑在线程隔离的上下文中重新排序指令是否安全,关于其他人的感知涉及线程
如果没有锁定或内存障碍,JMM只能保证在同一个线程中的语句之前发生。

在您的情况下,您在同一个对象(M)上有一个锁定机制,因此"发生在"之前"发生。
Java中的synchronized(锁定)或其他原子变量处理内存障碍原子性。 有关信息,构造函数中的volatile变量和final变量分配仅处理内存障碍。

以此example为例,根本不处理任何内存障碍:

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.