multithreading - Java volatile 读取可见性保证
问题描述
我在阅读 JVM 在读取 volatile 变量时提供的可见性保证时遇到了以下摘录: “当线程 A 写入 volatile 变量并且随后线程 B 读取相同的变量时,A 之前可见的所有变量的值在读取 volatile 变量后,写入 volatile 变量对 B 可见。”
我对 JVM 的这个保证有疑问。考虑以下一组类:
public class Test {
public static void main(String[] args) throws InterruptedException {
POJO p = new POJO();
new Th1(p).start();
new Th2(p).start();
}
}
public class Th1 extends Thread {
private POJO p1 = null;
public Th1(POJO obj) {
p1 = obj;
}
@Override
public void run() {
p1.a = 10; // t = 1
p1.b = 10; // t = 2
p1.c = 10; // t = 5;
System.out.println("p1.b val: " + p1.b); // t = 8
System.out.println("Thread Th1 finished"); // t = 9
}
}
public class Th2 extends Thread {
private POJO p2 = null;
public Th2(POJO obj) {
p2 = obj;
}
@Override
public void run() {
p2.a = 30; // t = 3
p2.b = 30; // t = 4
int x = p2.c; // t = 6
System.out.println("p2.b value: " + p2.b); // t = 7
}
}
public class POJO {
int a = 1;
int b = 1;
volatile int c = 1;
}
想象一下 2 个线程 Th1 和 Th2 在不同的 CPU 中运行,它们的指令执行顺序由每行中的注释指示(在它们的运行方法中)。我的问题是:当代码“int x = p2.c;”时 在 t = 6 时执行,线程 Th2 可见的变量应根据上述段落从主存储器刷新。据我了解,此时主存储器将拥有来自 Th1 的所有写入。变量 p2.b 在 t = 7 打印时会显示什么值?
- p2.b 的值是否会显示为 10,因为它的值是从 volatile 变量 p2.c 的读取中刷新的?
- 或者它会以某种方式保留值 30?
解决方案
对于您的代码,不保证 p2.b 为 10 或 30。写入是竞争条件。
“当线程 A 写入 volatile 变量并随后线程 B 读取相同的变量时,在写入 volatile 变量之前对 A 可见的所有变量的值在读取 volatile 变量后对 B 可见。”
不保证在将 p1.c 写入 Th1 之后完成对 p2.c 的 Th2 读取。
对于您讨论的特定顺序,在 Th2 中读取 p2.c不会将 p2.b 的值恢复为 10。
推荐阅读
- bash - bash - 将可选参数传递给脚本 - 参数名 + 字符串值
- java - 在整数索引 POI Java 中翻译字母(字符)索引
- android - HTTP 请求查询:我可以通过 HTTP 请求发送视频吗?并发送回 json 数据和图像?
- c# - ManagementBaseObject 和 ManagementObject 给出不同的 DeviceId
- powershell - 需要匹配2个CSV文件中的字段,然后根据一个字段的内容,返回另一个字段
- powerbi - Power BI:假设条件参数中的筛选器
- qnx - 用户如何调用超级用户命令?
- c# - C# asp.net 检查文本框是否包含空格
- azure - 通过 API 管理访问本地 API 的推荐方式,无需高级或开发人员层
- flutter - Flutter:如何更改 showTimePicker 小部件的颜色