考虑以下用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
不稳定会有什么变化? n
为java.util.List
会有什么变化(以便n = true
变为n.add("something")
且输出n=true
转换为{ {1}})?["something"]
为v
并且所有读取和写入都使用AtomicBoolean
语义执行,该怎么办?你能根据Java内存模型争论你的位置吗?
UPD:请将compareAndSet
视为System.out.println("n=" + n)
的读物。 n
也一样。
UPD2:您能否按照JSR-133秒的说明对第1和第4个案例进行分析。 8?
答案 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相同:它可能会也可能不会看到新值。非并发列表的示例:
set()
,则因为您无法在此类列表上拨打add()
) 如果列表是并发的,将看到新值。并发列表的示例: