为了原子地更新两个或更多的volatile变量,是否需要通过lock with synchronized,reentrantReadWriteLock等来保护?
即
volatile int vVar1, vVar1; // or AtomicInteger
/*** Needs to be updated atomically ***/
void atomicUpdate(int var1, int var2){
vVar1 = var1;
vVar2 = var2;
}
相同的代码适用于java.util.concurrent.atomic变量。
答案 0 :(得分:5)
如果您需要以原子方式分配两个值,则将volatile int
转换为AtomicInteger
将无法解决您的竞争条件问题。
要解决您的问题,您基本上有两个选择:
synchronized
(也许是读取这些变量的方法)选项2的示例:
volatile Vars vars;
void atomicUpdate(int var1, int var2) {
vars = new Vars(var1, var2);
}
public static Vars {
private int vVar1; // volatile if they need to be modified
private int vVar2;
}
我很喜欢选项2,因为它是非阻塞的,允许你缓存任何类型的数据。
答案 1 :(得分:3)
创建一个封装所有状态变量的类,然后使用AtomicReference来引用它们。这可以缓解线程需要安全地设置/检查多个值的竞争条件。
// set initial state
AtomicReference<MyState> ref = new AtomicReference<MyState>();
ref.set(new MyState("abc", "def"));
// .. Thread 1 needs to change the state:
ref.set(new MyState("xyz", "def"));
// .. Thread 2 needs to read the state (consistently):
MyState state = ref.get();
if ("test1".equals(state.a)) { }
else if ("test2".equals(state.b) { }
此处的好处是,Thread 2
能够从同一个MyState.a
实例一致地读取MyState.b
和MyState
,而不是MyState
个实例变量它引用了两次检查之间的变化。
答案 2 :(得分:2)
我想以原子方式更新我的两个变量
你做不到。 Java语言或Java标准库中没有跨越多个变量的原子操作。
您可以使用synchronized
关键字解决问题,但使用synchronized
与使用原子不同,因为为了使其工作,线程必须合作彼此。
如果在这两个变量(也就是不变)之间必须始终存在特定关系,并且如果不能暂时打破不变量而无法更新变量,然后您必须同步执行更新的代码,并且还必须同步每个其他需要不变量的代码块。
那是因为,当你写这篇文章时:
synchronized(foo) { ... }
除了同时在同一个对象上同步外,它不会阻止其他线程做任何事情。
另请注意:一旦您正确同步了对变量的所有访问权限,您就不需要它们volatile
。这是因为无论一个线程在释放锁之前写入内存,都可以保证对随后获取相同锁的任何其他线程可见。
答案 3 :(得分:1)
另一种方法是使用易失性数组:
private volatile int[] var;
void update (int var1, int var2) {
var = new int[] { var1, var2 };
}
这将是原子的,但它假定您的其余代码不直接访问vVar1和vVar2。根据您要实现的目标,可能有更好的选项 - 例如,您可以为两个整数创建一个临时线程安全持有者类(通常是不可变的)。