我想这样做:
- 读取 AtomicReference 中的值
- 基于旧值执行复杂的逻辑来创建新值
- 替换 AtomicReference 中的值
在此过程中,我希望其他线程等待直至完成。所以我需要给线程加一个读锁,逻辑完成后释放锁。
下面是我的尝试:
AtomicReference<String> version = new AtomicReference<>();
String v = version.get(); // Is there way to put a read lock here so that when other thread try to read it, they will have to wait until the current thread finish
if (v.equals("old")) {
String newVersion = getNewVersion(); // execute a complex logic
version.set(newVersion);
}
// release the lock here
最佳答案
像这样阻止所有读取线程(通过get
)是不可能的。您需要使用其他工具来执行此操作,并且需要在使用 version
的任何地方使用它们。
与您的想法最接近的事情是使用 AtomicReference
的原子方法,例如 updateAndGet
:
AtomicReference<String> version = new AtomicReference<>();
version.updateAndGet(v -> {
if (v.equals("old")) {
return getNewVersion();
}
else {
return v;
}
});
此方法利用原子 CAS指令实现non-blocking synchronization .
此方法的一个简单实现是:
public T updateAndGet(UnaryOperator<T> f) {
T curr, next;
do {
curr = get();
next = f.apply(curr);
} while (!compareAndSet(curr, next));
return next;
}
如果第一个给定参数等于实际当前值,则方法 compareAndSet
(即用于访问底层 CAS 指令的外观)返回 true
,否则 false
。如果第一个给定参数等于实际当前值,则当前值将替换为第二个参数(比较和交换)。
现在我为什么要解释这个?因为使用 updateAndGet
接近您想要的,但不一样:
getNewVersion
可能会运行多次。当当前值被curr = get();
和 CAS 调用之间的另一个线程更改时,就会发生这种情况。- 在
curr = get();
和 CAS 调用之间发生的读取会获取旧值,而不是像您的想法那样获取新值。不过这个时间跨度很小,不用担心。 - 不涉及锁,这是使用
AtomicXXX
类的最大好处之一。您希望它们轻量且快速。
关于java - 有没有办法对 AtomicReference 设置锁定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64593262/