摘自最终java
语义的field
文档:
他们保证会看到final
中设置的constructor
字段,请找到下面的代码:
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; // guaranteed to see 3
int j = f.y; // could see 0
}
}
}
现在我对volatile
与final
感到困惑。
根据我的理解,final
字段用于确保您无法在应用程序中更改变量,并且volatile
保证保持顺序并避免在发生关系之前发生。
所以我的问题是,它们如何使用final
变量而不是volatile
来保证可见性和排序?请帮助。
所以我的问题是,他们如何使用最终变量来保证可见性和顺序
因为他们是这样定义的,现在这是VM遵守此定义的工作。
当然,后续问题是:为什么他们用这种方式定义它?
这是由于Java内存模型的怪异“功能”。考虑这个例子
class Foo {
int x;
volatile int y;
Foo() {
x = 3;
y = 4;
}
static final Foo INSTANCE;
static {
INSTANCE= new Foo();
}
}
静态初始化器将被编译成这个(简化的伪代码):
Foo tmp = allocate(Foo.class)
Foo.INSTANCE = tmp
tmp.x = 3
tmp.y = 4
您可以看到,在执行构造函数之前,实例已公开,volatile
此处未做任何更改。
此行为对于大多数开发人员而言是意外的,并且可能导致非常难以调试的错误。因此,为了稍微减少此问题的扩展范围,对规范进行了调整,以要求在实例公开之前初始化最终字段。
上面的例子,x
声明为final
。
Foo tmp = allocate(Foo.class)
tmp.x = 3
Foo.INSTANCE = tmp
tmp.y = 4