英文:
Final fields Vs. Volatile
问题
从java
文档中关于final
字段语义的说明:
他们保证能够看到在构造函数
中设置的final
字段,请在下面找到代码:
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; // 保证看到3
int j = f.y; // 可能看到0
}
}
}
现在我对volatile
与final
有些困惑。
根据我的理解,final
字段用于确保您无法在应用程序中更改变量,而volatile
保证保持顺序并避免发生之前的关系。
那么我的问题是,他们如何通过使用final
变量而不是volatile
来保证可见性和顺序性呢?请帮忙解答。
英文:
From the java
docs of final field
semantics:
They are guaranteeing to see the final
field as set in constructor
, please find the code below:
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
}
}
}
Now here I am confused about volatile
vs final
.
To my understanding final
filed is used make sure you can not change the variable in application and volatile
guarantees to maintain the order and avoid happen before relationship.
So my question is how come they guarantee the visibility and ordering using final
variable instead of volatile
? Please help.
答案1
得分: 1
因为他们是这样定义的,现在虚拟机的工作是遵循这个定义。
当然,随后的问题是:为什么他们要这样定义呢?
这是因为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
在这里并没有改变任何内容。
这种行为对大多数开发者来说是意料之外的,可能会导致非常难以调试的错误。因此,为了在一定程度上减少这个问题,规范进行了调整,要求在实例变为公共实例之前必须初始化 final 字段。
以上是上述例子,其中 x
被声明为 final
。
Foo tmp = allocate(Foo.class)
tmp.x = 3
Foo.INSTANCE = tmp
tmp.y = 4
英文:
> So my question is how come they guarantee the visibility and ordering using final variable
Because they defined it that way, and it's now the job of the VM to adhere to this definition.
Of course, the follow-up question is: Why did they define it that way?
It's because of a weird "feature" of the Java memory model. Consider this example
class Foo {
int x;
volatile int y;
Foo() {
x = 3;
y = 4;
}
static final Foo INSTANCE;
static {
INSTANCE= new Foo();
}
}
The static intitializer will be compiled into this (simplified pseudocode):
Foo tmp = allocate(Foo.class)
Foo.INSTANCE = tmp
tmp.x = 3
tmp.y = 4
As you can see, the instance is made public before the constructor is executed, volatile
doesn't change anything here.
This behavior is unexpected for most developer and can lead to very hard-to-debug bugs. Thus, to reduce the extend of this issue a bit, the specification was adjusted to require final fields to be initialized before the instance is made public.
Example from above, with x
declared final
.
Foo tmp = allocate(Foo.class)
tmp.x = 3
Foo.INSTANCE = tmp
tmp.y = 4
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论