JMM 在实践中

JMM In Practice

考虑以下用Java编写的多线程代码:

共享变量:

         boolean n; // non-volatile
volatile boolean v; //     volatile

线程 1:

v = true;
System.out.println("n=" + n);

线程 2:

n = true;
System.out.println("v=" + v);

最初假设 n = v = false

现在:

您能根据 Java 记忆模型论证您的立场吗?

更新: 请将 System.out.println("n=" + n) 视为对 n 的阅读。 v.

也一样

UPD2: 您能否提供对第 1 和第 4 种情况的一些分析,如 JSR-133 秒所示。 8?

这里涉及两个因素。

  • 您有一个 volatile 字段,但是
  • 你有一个 synchronized 调用 System.out.println 这会起到 read/write 障碍

在两个线程中,您都在执行写入和读取。写入屏障并不能保证读取屏障。

Does the output of v=false imply the output of n=true?

如果您看到 v=false,您可能会看到 n=false,反之亦然

What would change if n were volatile?

不一定,您可能会看到行为发生变化,具体取决于您 运行 所在的体系结构,但是您仍然可以看到某些机器的不确定行为。

What would change if n were java.util.List

主要变化是您要替换写屏障,例如n = true with a read barrier n.method 这意味着你不再有写屏障(调用同步方法除外)

这样做意味着线程之间的一致性失败的原因更多。

实际上代码可以执行三种方式:

// Thread 1 runs first
T1: v = true;
T1: System.out.println("n=" + n);  // prints n=false

// Thread 2 runs second
T2: n = true;
T2: System.out.println("v=" + v);  // prints v=true
// They run in parallel, so assignments first, in any order
T1: v = true;
T2: n = true;

// Print statements second, in any order
T1: System.out.println("n=" + n);  // may print n=true or n=false (depends on CPU caching)
                                   // will print n=true if n is volatile
T2: System.out.println("v=" + v);  // prints v=true
// Thread 2 runs first
T2: n = true;
T2: System.out.println("v=" + v);  // prints v=false

// Thread 1 runs second
T1: v = true;
T1: System.out.println("n=" + n);  // may print n=true or n=false (depends on CPU caching)
                                   // will print n=true if n is volatile

Does the output of v=false imply the output of n=true?

没有。正如您在第三种情况中看到的,n 可能会打印任一值。

What would change if n were volatile?

如评论所述,n 将在场景 2 和 3 中打印 true,而不是不确定的。

What would change if n were java.util.List (so that n = true becomes n.add("something") and the output n=true transforms into ["something"])?

这假定 n 在场景开始之前已经是 List,因此 n 的波动性无关紧要。

n 的打印是否会看到插入的值取决于列表的类型。如果不是并发列表,答案与问题 1 相同:它可能会或可能不会看到新值。非并发列表的例子:

如果列表是并发的,它看到新值。并发列表示例: