【发布时间】:2015-09-08 18:07:32
【问题描述】:
我已经阅读了JCIP对第16.3节“初始化安全”的一些解释,但仍然不清楚。该部分指出
“此外,任何可以通过正确构造的对象的 final 字段到达的变量(例如 final 数组的元素或 final 字段引用的 HashMap 的内容)也保证是对其他线程可见。”
如果我有以下可变对象:
public final class Container{
private String name;
private int cupsWon;
private double netWorth;
public Container( String name, int cupsWon, double netWorth ){
this.name = name;
this.cupsWon = cupsWon;
this.netWorth = netWorth;
}
//NO Setters
//Getters
}
然后,Thread 1 如下创建它并将 c 传递给 Thread2。
final Container c = new Container("Ted Dibiasi", 10, 1000000);
Thread2(不是并发的,假设在 1 ms 之后),读取 c 的值,Thread2 是否有可能看到
c.name=null or
c.cupswon=0 or worst of all,
c.netWorth=0.0?
干杯
更新
我注意到有一些关于类有吸气剂的困惑。 我正在更新源代码,希望这会很清楚。 感谢大家观看。
public final class Container{
private String name;
private int cupsWon;
private double netWorth;
public Container( String name, int cupsWon, double netWorth ){
this.name = name;
this.cupsWon = cupsWon;
this.netWorth = netWorth;
}
public final String getName(){
return name;
}
public final int getCupsWon(){
return cupsWon;
}
public final double getNetWorth(){
return netWorth;
}
}
//---------
public final class Producer{
private final Client client;
public Producer( Client client ){
this.client = client;
}
//Thread1 call produce()
public final void produce( ){
final Container c = new Container("Ted Dibiasi", 10, 1000000);
client.update( c );
}
}
//----
public final class Client{
private Container c;
//private volatile Container c;
public final void update( Container c ){
this.c = c;
}
//Thread2 calls consume().
public final void consume( ){
String name = c.getName();
int cupsWon = c.getCupsWon();
double netWorth = c.getNetWorth();
}
}
我的问题是:
a) 当Thread2 调用consume() 时,name、cupsWon、netWorth 可以为null、0 还是0.0?我的想法是它可以,因为容器类中的字段不是最终的,所以没有可见性保证。
b) 但是,然后我阅读了第 16.3 节和关于“可以通过正确构造的对象的最终字段到达的变量”的部分,这是否意味着因为容器 c 的实例被宣布为最终的,我们确实在consume()中有可见性保证吗?
final 容器 c = new Container("Ted Dibiasi", 10, 1000000);
c) 将 Client 类中对 Container 的引用声明为 volatile 不会解决与引用相关的字段的可见性问题。
【问题讨论】:
-
由于构造是在通过之前发生的(否则如何才能通过?),我猜这是不可能的。
-
你能澄清一下是否有吸气剂吗?我认为您的意思是 有 getter 但 no setter,而有一个答案假设两者都没有。
-
@hiergiltdiestfu 是的,有 getter,但没有 setter。
-
此引用不适用于此处,因为没有最终字段。类的 final 不会影响各个字段。
-
@NathanHughes 我的想法很准确。由于没有一个字段是最终的,因此无法保证另一个线程将看到更新的值。我只是希望 JCIP 中的第 16.3 节措辞清楚一点。 ——
标签: java multithreading concurrency memory-visibility