在Java中,我理解volatile关键字提供变量的可见性.问题是,如果变量是对可变对象的引用,那么volatile还是为该对象内的成员提供了可见性吗?
在下面的示例中,如果多个线程正在访问volatile Mutable m并更改value?,它是否正常工作?
例
class Mutable {
private int value;
public int get()
{
return a;
}
public int set(int value)
{
this.value = value;
}
}
class Test {
public volatile Mutable m;
}
Run Code Online (Sandbox Code Playgroud) 如果存储在concurrentHashMap中,POJO对象中的可变字段是否安全?
或者我是否需要使用锁定来修改字段或使其变得易变,以确保所有线程都可以看到提升?将该字段标记为volatile是否足以确保所有线程都能看到更新?
我必须将线程之间的访问同步到共享对象,该对象的状态由几个字段组成。说:
class Shared{
String a; Integer b;
//constructor, getters and setters
....
}
Run Code Online (Sandbox Code Playgroud)
我可能有很多线程正在读取此对象,
//readers
shared.getA();
shared.getB();
Run Code Online (Sandbox Code Playgroud)
并且只有一个线程将在特定点写入:
//writer
shared.setA("state");
shared.setB(1);
Run Code Online (Sandbox Code Playgroud)
现在我的问题是如何确保读取线程不会在不一致状态下找到共享库。
我读过许多答案,它们表示为了volatile确保线程之间的一致性是解决方案,但我不确定它如何在多个字段上工作。例如,够了吗?
volatile String a; volatile Integer b;
Run Code Online (Sandbox Code Playgroud)
另一个解决方案是使共享对象不可变,并使用AtomicReference,
AtomicReference<Shared> shared = ....
Run Code Online (Sandbox Code Playgroud)
然后作者将交换引用:
Shared prev = shared.get();
Shared newValue = new Shared("state",1);
while (!shared.compareAndSet(prev, newValue))
Run Code Online (Sandbox Code Playgroud)
那是正确的方法吗?谢谢!
更新在我的设置中,共享对象是从检索的ConcurrentHashMap<Id,Shared>,因此注释同意使用的方法是使用不变方法或通过同步所有共享上的更新。但是,出于完整性考虑,很高兴知道上面的解决方案ConcurrentHashMap<Id,AtomicReference<Shared>>是可行的还是错误的,或者仅仅是多余的。有人可以解释吗?谢谢!
假设我们有一个列表参考:
volatile List<Object> a;
Run Code Online (Sandbox Code Playgroud)
现在线程1初始化它:
List<Object> newA = new LinkedList<>();
newA.add(new String("a"));
a = newA; // Write to a volatile (equivalent to exiting a synchronized block in terms of memory barriers)
Run Code Online (Sandbox Code Playgroud)
然后线程2做:
Object o = a.get(0); // Compound operation - first we read a volatile reference value, then invoke .get() method on it. Read to a volatile is equivalent to entering a synchronized block.
Run Code Online (Sandbox Code Playgroud)
"o"是否保证引用线程1添加的字符串?或者我错过了什么?假设来自线程1的代码在来自线程2的代码之前执行.