如何像CAS一样“'原子地验证和懒惰交换'?

时间:2017-08-03 13:50:19

标签: java multithreading atomic compare-and-swap

这是我想要的功能原型:

atomicReference.validateAndSwap(value -> isInvalid(value), () -> createValid());

假设从多个线程调用 仅在第一次返回true时才调用第二个lambda 第一个(加上第二个,如果第一个返回true)lambda调用应该是单个原子操作。

甚至可以在没有synchronized的情况下实施? 有类似功能的现成解决方案吗? 我错误的思考方式并错过了一些东西吗?

1 个答案:

答案 0 :(得分:1)

我不确定在说“ First(加上第二次,如果第一次返回true)时,你的意思是正确的吗?lambda调用应该是一个单独的原子操作。”原子引用的重点在于更新函数评估可能重叠,因此,不应该有干扰,但会像原子一样,因为当评估重叠时,只有一个可以成功CAS而另一个必须是根据新值重复。

如果您想要真正的原子评估,使用Locksynchronized是不可避免的。如果你有适当的非干扰函数,并希望实现更新,就像原子一样,它可以像

一样实现
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);

实现相同的目标,但它也不是真正的原子,而是如果对更新函数的并发评估没有干扰则表现为原子。