Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/359.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';s volatile关键字";递归的;关于引用树,还是必须将每个引用声明为volatile?_Java_Multithreading_Volatile - Fatal编程技术网

是Java';s volatile关键字";递归的;关于引用树,还是必须将每个引用声明为volatile?

是Java';s volatile关键字";递归的;关于引用树,还是必须将每个引用声明为volatile?,java,multithreading,volatile,Java,Multithreading,Volatile,考虑以下玩具示例类: public class Test { private volatile Outer outerVar = new Outer(); static class Outer { Inner innerVar = new Inner(); } static class Inner { // state // setters // getters } p

考虑以下玩具示例类:

public class Test {

    private volatile Outer outerVar = new Outer();

    static class Outer {
        Inner innerVar = new Inner();
    }

    static class Inner {

        // state

        // setters

        // getters

    }

    private void multithreadedUse() {
        // play with outerVar.innerVar
    }
}
outerVar是易变的,因此所有可能正在使用它的线程都会看到它处于相同的状态。但是outerVar.innerVar呢?它的父对象(outerVar)被标记为volatile这一事实是否也会使它变得不稳定

或者我们必须显式地声明innerVar volatile吗

但是outerVar.innerVar呢?它的父对象(outerVar)被标记为volatile这一事实是否也会使它变得不稳定

在本例中,
outerVar.innerVar
将正确发布,但它不会是易失性的。如果您在稍后的某个时间分配
outerVar.innerVar=new internal()
,您将丢失线程安全出版物

这里的规则是,在易失性写入之前发生的所有写入都在易失性写入之后可见。写入之后,所有正常写入现在都是线程不安全的

因此,在您的示例中,从线程进行排序将看到类似于

volatile Outer outerVar;
Outer temp = new Outer();
temp.innerVal = new Inner()
outerVar = temp;
注意
outVar=temp
的易失性写入。这就是同步开始的地方。当另一个线程读取非空的outerVar实例时,innerVar字段将安全发布

不过重申一下,任何时候为
outerVar.innerVal
指定一个新值时,都会丢失同步。类似地,如果
innerVal
有任何字段[在初始volatile写入之后],对这些字段的写入将不会正确同步

所以我来回答你的问题

关于引用树,Java的volatile关键字是“recursive”吗 必须将每个引用声明为volatile吗


每个字段都必须声明为volatile,在初始volatile写入(从技术上讲)后将发生更改。也就是说,如果在线程之间共享,则应该声明volatile或final字段。

您对volatile的理解是正确的,您对外部类对象的期望也是正确的。但是,外部类的属性不能免疫线程安全,这确实违背了volatile的目的。解决这种情况的最佳方法是使内部变量不可变。这就是volatile布尔包装器和字符串的工作方式。使内部状态不可变且为最终状态,使易失性对象线程安全,因此可以自由使用

但是仍然有很多人希望坚持使用代码,那么只要不改变外部类实例化后的属性,就可以了。但这本质上也是最终性和不变性的含义


查看这篇关于线程安全基础知识的文章。

您好,只要我不修改innerVar引用,一切都好吗?但如果我这样做了,我必须声明它本身是易变的,对吗?是的,这是完全正确的。如果你能宣布它是最终的,那么你应该。