4

我看过这个答案,它说明了如何:

在新的内存模型下,当线程 A 写入 volatile 变量 V,而线程 B 从 V 中读取时,在写入 V 时对 A 可见的任何变量值现在都保证对 B 可见。

因此,举个例子:

public class Main {
    static int value = -1;
    static volatile boolean read;

    public static void main(String[] args) {
        Thread a = new Thread(() -> {
            value = 1;
            read = true;
        });

        Thread b = new Thread(() -> {
            while (!read);

            System.out.println("Value: " + value);
        });

        a.start();
        b.start();
    }
}

尽管(only )value的非易失性,是否保证对 (从 -1 到 1) 的更改对线程 b 可见?valueread

如果是这样,考虑到为了对另一个线程可见而执行的一堆更改,除了最后一个易失性之外,是否有任何目的更改任何变量?

4

1 回答 1

5

是的,对线程 b 的更改value保证是可见的。

JLS 17.4.4。同步订单说:

  • 对 volatile 变量v(第 8.3.1.4 节)的写入与任何线程对v的所有后续读取同步(其中“后续”根据同步顺序定义)。

JLS 17.4.5。订单前发生说:

两个动作可以通过happens-before关系排序。如果一个动作发生在另一个动作之前,那么第一个动作对第二个动作可见并在第二个动作之前排序。

如果我们有两个动作xy,我们写hb(x, y)来表示x 发生在 y 之前

  • 如果xy是同一线程的操作,并且x在程序顺序中位于y之前,则为 hb(x, y)

  • 从对象的构造函数的末尾到该对象的终结器(第 12.6 节)的开头有一条发生前边缘。

  • 如果动作x 与后续动作y同步,那么我们也有hb(x, y)

  • 如果hb(x, y)hb(y, z),则hb(x, z)

项目符号 1 说value = 1 发生在之前 read = true
Bullet 3 说read = true 发生在之前 !read
项目符号 1 说!read 发生在之前 "Value: " + value
Bullet 4 说value = 1 发生在之前 "Value: " + value

于 2018-09-26T04:05:06.783 回答