我已经从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毫秒后),读取c的值,Thread2是否有可能看到
c.name=null or
c.cupswon=0 or worst of all,
c.netWorth=0.0?
干杯
更新
我注意到类有 setter/getter 有些困惑。
我正在更新源代码,希望这会很清楚。
谢谢大家的光临。
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 调用define()时,name,cupsWon,netWorth可以为null,0或0.0吗?我的想法是可以使用可以使用,因为容器类中的字段不是最终的,因此不提供可见性保证。
b)但是,然后我阅读了16.3节和有关“可以通过正确构造的对象的final字段访问的变量”的内容,这是否意味着因为容器c的实例被声明为final,所以我们 DO 有在consumer()中的可见性保证吗?
最终容器c = new Container(“Ted Dibiasi”,10,1000000);
c)在Client类中将对Container的引用声明为volatile将不会解决与引用有关的字段的可见性问题。
最佳答案
final Container c = new Container("Ted Dibiasi", 10, 1000000);
如果此处的c
是Thread1
中的最后一个字段,而不是局部变量,则来自Java Language Specification的引号适用于此最终字段c
:尽管这里的措词含糊,但我认为“正确初始化的值”和“最新的最终字段”意味着,如果将
c
传递给Thread2
构造函数之外的Thread1
,则Thread2
始终会看到完整的构造字段已初始化的Container
实例。关于java - 可见性保证,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32464456/