Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 能见度保证_Java_Multithreading_Concurrency_Memory Visibility - Fatal编程技术网

Java 能见度保证

Java 能见度保证,java,multithreading,concurrency,memory-visibility,Java,Multithreading,Concurrency,Memory Visibility,我已经阅读了JCIP关于第16.3节“初始化安全”的一些解释,但仍然不清楚。该节指出: “此外,通过正确构造的对象的最终字段(如最终数组的元素或最终字段引用的哈希映射的内容)可以访问的任何变量也保证对其他线程可见。” 因此,如果我有以下可变对象: public final class Container{ private String name; private int cupsWon; private double netWorth; public C

我已经阅读了JCIP关于第16.3节“初始化安全”的一些解释,但仍然不清楚。该节指出:

“此外,通过正确构造的对象的最终字段(如最终数组的元素或最终字段引用的哈希映射的内容)可以访问的任何变量也保证对其他线程可见。”

因此,如果我有以下可变对象:

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传递给线程2

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?
干杯

更新 我注意到班上有些人对有能手感到困惑。 我正在更新源代码,希望这将是明确的。 谢谢大家的关注

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;
    }

}
//----------

//----

我的问题是:

a) Thread2调用consume()时,name、cupsWon、netWorth是否可以为null、0或0.0?我的想法是,它可以,因为容器类中的字段不是最终字段,所以没有可见性保证

b) 然而,然后我阅读了第16.3节和关于“变量可以通过正确构造的对象的final字段访问”,这是否意味着因为容器c的实例被声明为final,所以我们在consume()中有可见性保证

最终集装箱c=新集装箱(“Ted Dibiasi”,101000)

c) 将对客户端类中容器的引用声明为volatile不会解决字段的可见性问题,因为它与引用有关

final Container c = new Container("Ted Dibiasi", 10, 1000000);
如果
c
此处是
Thread1
中的最后一个字段,而不是局部变量,则引用自适用于该最后一个字段
c

当一个对象的构造函数完成时,它被认为是完全初始化的。只有在对象完全初始化后才能看到该对象引用的线程才能保证看到该对象最终字段的正确初始化值

final Container c = new Container("Ted Dibiasi", 10, 1000000);
final字段的使用模型很简单:在对象的构造函数中为对象设置final字段;并且在对象的构造函数完成之前,不要在另一个线程可以看到的地方编写对正在构造的对象的引用。如果遵循这一点,那么当另一个线程看到该对象时,该线程将始终看到该对象最终字段的正确构造版本它还将看到最终字段引用的任何对象或数组的版本,这些版本至少与最终字段一样最新。


虽然这里的措辞含糊不清,但我认为“正确初始化值”和“作为最终字段的最新值”意味着如果您将
c
传递给
Thread2
构造函数之外的
Thread1
构造函数,
Thread2
将始终看到一个完全构造的
容器
实例,其字段已初始化。

程序员通常不需要担心这个问题。只有当对象“不安全地发布”时才有问题,例如,线程1将对象分配给非易失性静态字段,线程2从读取非易失性字段中检索对象。然而,这种情况很少发生;对象在线程之间传递几乎总是带有一些内存障碍。例如,将对象传递给ThreadPoolExecutor时,不需要担心可见性

应该不惜一切代价避免不安全的出版物,除非您确实需要它,并且您确切地知道自己在做什么

除非有充分的理由,否则类通常不需要设计为能够承受不安全的发布。例如,
String
就是这样设计的,因为它在核心安全/访问控制代码中被广泛使用,而且字符串的内容必须保持不变,即使一些恶意程序试图通过不安全的发布来破坏它


大多数类不需要使用
final
字段来抵抗不安全的发布

要回答您的问题,Thread2永远不会看到容器字段处于未初始化状态。原因是容器的构造函数在参考容器c变得可访问之前完全运行。调用
Client.update
Client.consume
之间可能存在竞争条件。根据此竞争的结果,在调用
Client.consume中的
c.getName()
时,字段
c
要么为空,要么为完全初始化的容器对象。在第一种情况下,您得到一个NullPointerException,在第二种情况下,得到正确初始化的值。我认为这与JCIP引用的句子没有任何关系。

因为这个构造发生在通过之前(如果不是这样,它怎么会通过?),我猜这是不可能的。你能澄清一下是否有getter吗?我想你的意思是有getter但没有setter,而答案是假设两者都没有。@hiergiltdiestfu是的,有getter但没有setter。这里的引号不适用,因为没有最终字段。“课程的期末考试不会影响各个领域。”纳森准确地表达了我的想法。由于所有字段都不是最终字段,因此无法保证另一个线程将看到更新的值。我只希望JCIP中的第16.3节措辞清楚一点但字段不是最终的!本例中的最终字段是
Final Container c=新容器(“Ted Dibiasi”,101000)因此容器实例是
Thread1
的最后一个字段引用的对象。而且内存模型保证它处于lea
final Container c = new Container("Ted Dibiasi", 10, 1000000);