我已经从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);
如果此处的cThread1中的最后一个字段,而不是局部变量,则来自Java Language Specification的引号适用于此最终字段c:

尽管这里的措词含糊,但我认为“正确初始化的值”和“最新的最终字段”意味着,如果将c传递给Thread2构造函数之外的Thread1,则Thread2始终会看到完整的构造字段已初始化的Container实例。

关于java - 可见性保证,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32464456/

10-13 00:39