多个字段:volatile还是AtomicReference?

leg*_*ass 5 java concurrency multithreading atomicity atomicreference

我必须将线程之间的访问同步到共享对象,该对象的状态由几个字段组成。说:

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>>是可行的还是错误的,或者仅仅是多余的。有人可以解释吗?谢谢!

Mik*_*ail 1

首先你应该使其Shared不可变:

class Shared{
   private final String a; 
   private final int b;
   //constructor, getters and NO setters
}
Run Code Online (Sandbox Code Playgroud)

如果你只有一个 writer,你可以安全地使用 volatile,那么 AtomicReference 就没有必要了。在信息更新时,不应修改旧对象,而应创建新对象并将其分配给易失性引用。