Java thread.start 可以重新排序吗?

Could Java thread.start be reordered?

考虑从 Memory Consistency - happens-before relationship in Java 借用的以下场景:

package happen.before;

public class HappenBeforeRelationship {

private static int counter = 0;

private static void threadPrintMessage(String msg){
    System.out.printf("[Thread %s] %s\n", Thread.currentThread().getName(), msg);
}

public static void main(String[] args) {
    threadPrintMessage("Increase counter: " + ++counter);
    Thread t = new Thread(new CounterRunnable());
    t.start();
    try {
        t.join();
    } catch (InterruptedException e) {
        threadPrintMessage("Counter is interrupted");
    }
    threadPrintMessage("Finish count: " + counter);
}

private static class CounterRunnable implements Runnable {
    @Override
    public void run() {
        threadPrintMessage("start count: " + counter);
        counter++;
        threadPrintMessage("stop count: " + counter);
    }
}

我知道 JLS 中有一条规则保证 Thread.start 在启动线程中的所有操作之前发生。

When a statement invokes Thread.start, every statement that has a happens-before relationship with that statement also has a happens-before relationship with every statement executed by the new thread. The effects of the code that led up to the creation of the new thread are visible to the new thread.

但它并没有声称Thread.start之前的语句与它有happens-before关系。

所以我想知道是否可以 Thread.start 重新排序以使程序无法获得预期的输出(计数器=2)?如果不是,JLS 的哪一部分指定 Thread.start 不能重新排序?


另一个问题:

如果 join() 放在 threadPrintMessage("Finish count: " + counter); 之后会怎样?有没有可能打印出stop count: 1

由于JLS§17.4.5:

Thread.start调用前的动作与新线程启动之间存在顺序关系
  • If x and y are actions of the same thread and x comes before y in program order, then hb(x, y).
  • If hb(x, y) and hb(y, z), then hb(x, z).

稍后在同一部分中,您的问题保证中已经提到:

  • A call to start() on a thread happens-before any actions in the started thread.

由于 happens-before 关系的传递性质,主线程的操作之间有一个 happens-before 关系在调用 start() 和启动线程中的操作之前。同样,在启动线程的操作和主线程的 成功 return 之间存在 happens-before 关系13=]调用。

换句话说,只要您没有遇到 InterruptedException,更新就会正确排序,打印结果将是 2。然而,这并不意味着这些操作永远不会随着 JLS§17.4.5 的继续而重新排序:

It should be noted that the presence of a happens-before relationship between two actions does not necessarily imply that they have to take place in that order in an implementation. If the reordering produces results consistent with a legal execution, it is not illegal.

换句话说,happens-before 关系是一个高级概念,它允许您确定程序执行的合法结果。如果像这个例子一样,在程序末尾的 counter 中包含 2 是唯一合法的结果(如前所述,假设没有发生中断),JVM 可能会尽可能多地安排代码如其所愿,只要该程序将在最后的 counter 中产生具有 2 的合法结果。

您应该停止为可以重新订购或不可以重新订购而烦恼。这是一个不重要的实现细节。如果没有适当的 happens-before 关系,您可能会遇到出现乱序的更新,但也可能会错过更新或创建不一致的状态,因此专注于一个没有意义可能导致程序损坏的意外副作用的实现细节。相反,专注于什么是正确的程序。