请考虑以下代码:
import java.util.concurrent.Callable;
final public class DelayedSet {
String Val = "Uninitialized";
public Callable<String> Makegetter(String val) {
this.Val = val;
return new Callable<String>() {
public String call() {
return DelayedSet.this.Val;
}
};
}
}
class Main {
public static void main(String[] args) {
DelayedSet x = new DelayedSet();
Callable<String> Foogetter = x.Makegetter("Initialized");
// Version 1
try {
System.out.println(Foogetter.call());
}
catch (Exception e) {
}
}
}
运行Main后,将打印“已初始化”。
现在考虑变体A ,其中Foogetter
被传递给新的线程。那么Foogetter
是否也会返回“已初始化”,或者由于过时的缓存条件,Foogetter
是否可以返回“未初始化”?
还要考虑变体B ,其中我们有三个主题T1
,T2
和T3
。 T1
,通过期货,向Callable
提交T2
,其中T2
创建DelayedSet
,调用Makegetter
,然后返回"Foogetter"
(在技术上匿名的引号中)通过将来回到T1
。 T1
然后获取此结果("Foogetter"
),并提交另一个可调用者,这次是T3
,其中T3
调用"Foogetter"
。对于这两种变体,是否保证将返回“已初始化”或者是否可以返回“未初始化”?
总结psuedocode:
T1:
futureT2 = executorService.submit(new Callable {
...
call() {
// Runs in T2
Foo = new DelayedSet;
return Foo.Makegetter("Initialized");
} ...
futureT3 = executorService.submit(futureT2.get());
print(futureT3.get());
来自这个question,我得到的印象是,人们需要依赖同步事件来捎带,例如volatile或synchronized块。但是,我正在尝试确定不需要挥发物的特殊情况(即使是通过捎带),但是由于在线程创建和加入的语义之前发生,不会产生任何过时的缓存条件。
为了回答这个问题,有人可以澄清关于线程的内存模型是什么吗?
答案 0 :(得分:1)
对于 Variant A ,我会假设
new Thread(() -> {
try {
System.out.println(Foogetter.call());
} catch (Exception e) {
}
}).start();
在这种情况下,the JLS has us covered
在启动线程中的任何操作之前,对线程的start()调用发生。
this.Val = val;
发生在调用Makegetter
之前发生的Thread#start()
调用中,然后在启动的线程中调用call
之前发生。返回的值必须始终为"Initialized"
。
在变体B 中,首先要注意的是Future
的内存一致性效果
异步计算采取的操作发生在操作之前 在另一个帖子中跟随相应的
Future.get()
。
当futureT2.get()
返回T1
时,call
中的T2
调用已经发生( - 之前)并且MakeGetter
的调用已经设置DelayedSet.Val
的值。 T1
可以看到此更改,Callable
和T3
会返回此更新后的值,并再次T1
,futureT3.get()
会将其检索到。{/ { p>