我已经阅读了JCIP对第16.3节“初始化安全”的一些解释,但仍然不清楚。该部分指出
“此外,可以通过正确构造的对象的最终字段(例如最终数组的元素或最终字段引用的 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
}
然后,线程 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?我的想法是它可以,因为 Container 类中的字段不是最终的,因此没有可见性保证。
b)但是,然后我阅读了第 16.3 节和有关“可以通过正确构造的对象的最终字段到达的变量”的内容,这是否意味着因为容器 c 的实例被声明为最终的,所以我们确实有可见性保证消耗()?
final Container c = new Container("Ted Dibiasi", 10, 1000000);
c) 将 Client 类中对 Container 的引用声明为 volatile 不会解决与引用相关的字段的可见性问题。