java - Java最终和安全发布
问题描述
当我阅读jsr-133-faq时,有疑问“最终字段如何在新 JMM 下工作?”,它说:
class FinalFieldExample {
final int x;
int y;
static FinalFieldExample f;
public FinalFieldExample() {
x = 3;
y = 4;
}
static void writer() {
f = new FinalFieldExample();
}
static void reader() {
if (f != null) {
int i = f.x;
int j = f.y;
}
}
}
上面的类是如何使用 final 字段的示例。保证执行 reader 的线程看到 fx 的值 3,因为它是最终的。不能保证看到 y 的值 4,因为它不是最终值。
这让我很困惑,因为 writer 中的代码不是安全发布的,线程执行 reader 可能会看到 f 不是 null,但是 f 引用的对象的构造函数还没有完成,所以即使 x 是 final,线程执行 reader不能保证看到 fx 的值 3
这是我很困惑的地方,如果我错了,请纠正我,非常感谢。
解决方案
这就是重点,这就是 JMM 中 final 字段的优点。是的,编译器通常可以在对象完全构造之前分配对对象的引用,这是不安全的发布,因为可以在部分构造状态下访问对象。但是,对于final字段,JMM(和编译器)保证在将引用分配给对象之前首先准备好所有 final 字段。发布可能仍然不安全,并且当新线程访问它时,对象仍然只是部分构造,但至少最终字段将处于其预期状态。来自 Java Concurrency in Practice 的第 16.3 章:
初始化安全性仅对构造函数完成时可通过 final 字段访问的值提供可见性保证。对于可通过非最终字段访问的值,或构造后可能更改的值,您必须使用同步来确保可见性。
我还建议阅读第 16.3 章了解更多详细信息。
推荐阅读
- amazon-web-services - 如何使用 Terraform 传递 AssumeRole 并将 SSM 文档与 EC2 关联
- sql - 使用循环一次更新 100 万条数据
- javascript - 如何在 onClientClick 事件的函数内评估值
- http - Jenkins http请求无法识别文件名
- amazon-web-services - 如何在不同安全组中的 2 个实例之间共享文件?
- tensorflow - 具有手臂特征的 TF-Agents Bandits
- r - 当某些 ID 值为空白时,如何从长转换为宽?
- python - 我想制作每个服务器频道
- python - 协议缓冲区/JSON 模式到 SQL DDL
- c++ - Qt c++ 标签不显示新文本