java - Java中的happens-before机制

标签 java multithreading volatile java-memory-model

我有关于 Java 中的 happens-before 机制的问题。这是示例:

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);
        }


    }

这是 happens-before 的明显例子,据我所知,这是足够安全的。 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 并让 write 在将值设置为 之后将值设置为 b >a 保证:

  1. 如果ba之前被读取,那么
  2. a 的值不会早于 b 之前写入时的值。

也就是说,写入 b 和从 b 读取充当同步点或栅栏,这意味着写入 a 的任何内容code> 在写入 b 之前将在从 b 读取之后可读(如果 a 被写入多次,则以下写入可能或者可能不可见)。

但是,您的代码并不像现在这样安全。在 read 中,您有以下表达式:

a + " " + b

在 Java 中,expressions are evaluated left-to-right .这意味着,a 将在 b 之前被评估。因此,完全有可能读取 a 将看到 a 的旧值,而读取 b 将看到一个新值b。如果您在 a 之前读取了 b,则 b 的写入和读取之间的发生前关系将覆盖对 的写入a 和从 a 中读取。现在,它没有。

至于 write 中的重新排序操作 - 这将明显消除 b 的排序保证对 a 操作的影响,即使read先读b,再读a

为了可视化事物,仅给定 bvolatile:

当前代码不保证 - 上的操作顺序

write a                         read a
write b --> happens before -->  read b

使用给定的读取重新排序 write 也不会对 a 进行排序 -

                                read a
write b --> happens before -->  read b
write a

即使给定的 read 是固定的,a 也不会按 b 排序 -

write b --> happens before -->  read b
write a                         read a

唯一安全的做法是保持当前的write,并修复read -

write a
write b --> happens before -->  read b
                                read a

关于java - Java中的happens-before机制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25098539/

相关文章:

java - 我如何将 css 放在 spring 元素的 Hibernate validator 注释消息的消息上

java - "error: cannot find symbol HashMap"

c# - 我应该如何调试检查将来有效的假设?

java - 程序顺序规则在构造函数中起作用之前是否发生?

c# - 为什么 readonly 和 volatile 修饰符是互斥的?

actor - 我的 Akka Actor 的属性是否应该标记为 @volatile?

java - 为什么不能在这里使用 'this' 关键字?

java - 在Java中调用Kotlin时如何省略构造函数参数的默认值?

.net - 线程安全无锁互字节数组队列

java - volatile 变量和同步 setter 和 getter