JMM在实践中

时间:2016-08-26 23:33:14

标签: java multithreading java-memory-model happens-before

考虑以下用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不稳定会有什么变化?
  • 如果njava.util.List 会有什么变化(以便n = true变为n.add("something")且输出n=true转换为{ {1}})?
  • UPD3 :如果["something"]v并且所有读取和写入都使用AtomicBoolean语义执行,该怎么办?

你能根据Java内存模型争论你的位置吗?

UPD:请将compareAndSet视为System.out.println("n=" + n)的读物。 n也一样。

UPD2:您能否按照JSR-133秒的说明对第1和第4个案例进行分析。 8?

2 个答案:

答案 0 :(得分:2)

这里涉及两个因素。

  • 您有synchronized字段,但
  • 您对System.out.println进行v=false调用此行为是读/写屏障

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

  

v = false的输出是否意味着输出n = true?

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

  

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

实际上,根据您运行的体系结构,您可能会看到行为更改,但您仍然可以看到某些计算机的不确定行为。

  

如果n是java.util.List

,会发生什么变化

主要的变化是你正在取代写屏障,例如n.method带有读屏障average_assignment_grade = sum(x) + midTermGrade + finalGrade / 7 这意味着您不再有写屏障(除了调用同步方法)

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

答案 1 :(得分: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已经是List,因此n的波动性并不重要。

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

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