这是我想要的函数原型(prototype):
atomicReference.validateAndSwap(value -> isInvalid(value), () -> createValid());
它假定从多个线程调用。
第二个 lambda 仅在第一个返回 true
时被调用。
首先(如果第一个返回 true
,则加上第二个)lambda 调用应该是单个原子操作。
甚至可以不用synchronized
来实现?
是否有类似功能的现成解决方案?
我是否有错误的思维方式并错过了什么?
最佳答案
我不确定您说“第一个(如果第一个返回 true 则加上第二个)lambda 调用应该是单个原子操作。”的意思是否正确。原子引用的要点是更新函数评估可能重叠,因此不应有干扰,但会像原子一样运行,因为当评估重叠时,只有一个可以通过 CAS
成功,另一个可以成功必须根据新值重复。
如果你想要真正的原子计算,使用 Lock
或 synchronized
是不可避免的。如果你有适当的非干扰函数并且想要像原子一样实现更新,它可以像这样实现
Value old;
do old = atomicReference.get();
while(isInvalid(old) && !atomicReference.compareAndSet(old, createValid()));
由于在这种特定情况下,createValid()
函数不依赖于旧值,我们可以避免在竞争情况下重复求值:
Value old = atomicReference.get();
if(isInvalid(old)) {
Value newValue = createValid();
while(!atomicReference.compareAndSet(old, newValue)) {
old=atomicReference.get();
if(!isInvalid(old)) break;
}
}
所有这些都假设对象的有效性不能在两者之间改变。否则,锁定或同步是不可避免的。
请注意,Java 8 的更新方法遵循相同的原则。所以你可以写
atomicReference.updateAndGet(old -> isInvalid(old)? createValid(): old);
实现相同,但它也不是真正的原子,而是如果更新函数的并发评估没有干扰,则表现得好像是原子的。
关于java - 如何 "' 像 CAS 一样以原子方式验证和惰性交换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45486206/