我读了jsr166中的FutureTask类,发现outcome对象是non-volatile的,代码中的注释是“non-volatile, protected by state reads/writes”第75行,state是volatile int。我已经从 Java Language Spec 阅读了 Java 内存模型,但没有找到准确的答案。有人知道原因吗?
最佳答案
考虑这个程序:
volatile int state;
Integer result;
void succeed(Integer result)
if(state==PENDING) vr0
this.result = result; w1
state = DONE; vw1
Integer peekResult()
if(state==DONE) vr2
return result; r2
return null;
如果 volatile read vr2
看到DONE
,这意味着它发生在 volatile write vw1
之后。所以我们有 happens-before 关系:w1 -> vw1 -> vr2 -> r2
。因此写w1
对读r2
是可见的。
然而 succeed()
不是线程安全的,因为 vr0
和 vw1
不是原子的。如果我们使用 CAS
void succeed(Integer result)
if( compareAndSet(state, PENDING, DONE) ) vr0+vw0
this.result = result; w1
它修复了原子性问题。但是,现在 w1
不一定对 r2
可见。 CAS的内存屏障效应有点像
void succeed(Integer result)
if(state==PENDING) vr0
state=DONE; vw0
this.result = result; w1
我们这里有vw0 -> vr2 -> r2
,但是w1
不在链上,没有w1 -> r2
我们必须在 w1
之后执行 volatile 写入 state=DONE
以建立 happens-before 链。
void succeed(Integer result)
if(state==PENDING) vr0
state=TMP; vw0
this.result = result; w1
state=DONE; vw1
或在 CAS 中
void succeed(Integer result)
if( compareAndSet(state, PENDING, TMP) ) vr0+vw0
this.result = result; w1
state=DONE; vw1
关于java - 为什么 FutureTask 中的结果对象是非 volatile 的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14432400/