是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引用,一切都好吗?但如果我这样做了,我必须声明它本身是易变的,对吗?是的,这是完全正确的。如果你能宣布它是最终的,那么你应该。