3

考虑以下用 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

现在:

  • 的输出是否v=false暗示 的输出n=true
  • n如果是 volatile会发生什么变化?
  • n如果是的话会发生什么变化java.util.List(这样n = true就变成n.add("something")了并且输出n=true变成了["something"])?
  • UPD3:如果所有对它vAtomicBoolean读取和写入都使用compareAndSet语义执行会怎样?

你能根据 Java 内存模型论证你的立场吗?

UPD:System.out.println("n=" + n)视为只是阅读n. 对于v.

UPD2:您能否对 JSR-133 sec 中所示的第 1 和第 4 种情况进行一些分析。8?

4

2 回答 2

2

这里涉及两个因素。

  • 你有一个volatile领域,但是
  • 你有一个synchronized电话System.out.println这行为读/写障碍

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

v=false 的输出是否暗示 n=true 的输出?

如果你看到v=false你可能会看到 an=false反之亦然

如果 n 不稳定,会发生什么变化?

并非如此,您可能会看到行为发生变化,具体取决于您运行的架构,但是您仍然可以看到某些机器的不确定行为。

如果 n 是 java.util.List 会发生什么变化

主要变化是您正在替换写屏障,例如n = true用读屏障n.method 这意味着您不再有写屏障(对同步方法的调用除外)

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

于 2016-08-27T00:01:57.030 回答
0

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

// 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

v=false 的输出是否暗示 n=true 的输出?

不。正如您在第三种情况中看到的那样,n可以打印任一值。

如果 n 不稳定,会发生什么变化?

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

如果 n 是 java.util.List 会发生什么变化(因此 n = true 变为 n.add("something") 并且输出 n=true 转换为 ["something"])?

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

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

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

于 2016-08-27T00:43:05.827 回答