这是我想要的功能原型:
atomicReference.validateAndSwap(value -> isInvalid(value), () -> createValid());
假设从多个线程调用
仅在第一次返回true
时才调用第二个lambda
第一个(加上第二个,如果第一个返回true
)lambda调用应该是单个原子操作。
甚至可以在没有synchronized
的情况下实施?
有类似功能的现成解决方案吗?
我错误的思考方式并错过了一些东西吗?
答案 0 :(得分:1)
我不确定在说“ First(加上第二次,如果第一次返回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);
实现相同的目标,但它也不是真正的原子,而是如果对更新函数的并发评估没有干扰则表现为原子。