如何像 CAS 一样“原子地验证和延迟交换”?

Posted

技术标签:

【中文标题】如何像 CAS 一样“原子地验证和延迟交换”?【英文标题】:How to "'validate and lazy swap' atomically" like CAS? 【发布时间】:2017-08-03 13:50:18 【问题描述】:

这是我想要的函数原型:

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

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

甚至可以不用synchronized来实现? 是否有针对类似功能的现成解决方案? 我是不是思维方式不对,错过了什么?

【问题讨论】:

"不同步也可以实现?" - 不。 这里的对象是不可变的吗?如果不是,它们的“有效性”至少是不变的吗?如果两个答案都是“否”,那么我怀疑你忽略了一些关于安全共享可变状态的非常基本的东西。如果任一答案为“是”,这可能是可能的,但它需要您放宽对 lambdas 调用作为原子单元发生的要求。如果有效性确实是不可变的,那应该不是问题,除非您坚持不产生垃圾。 另外,如果您可以提供更多关于您最终想要做什么的背景信息,我们可以提供更多有用的反馈,并可能为这项工作推荐一个更好的“工具”。 【参考方案1】:

我不确定您所说的“第一个(如果第一个返回 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);

达到同样的效果,但它也不是真正的原子,而是在更新函数的并发评估没有干扰的情况下表现得好像是原子的。

【讨论】:

如果对象不能在两者之间改变,那么while(isInvalid(old) && !atomicReference.compareAndSet(old, createValid())) 的意义何在? @Eugene:这是一个do … while 循环;这就是我缩进while 行的原因。不幸的是,它不适合一行。 我的意思是不同的,但我想我现在明白了。这实际上非常好,所以如果isInvalid 返回 true,那么您正在尝试使用有效的 CAS old;如果失败,则意味着 atomicReference 已更改(很可能具有有效值)。而您正在再次尝试,但首先检查该值是否有效...... 第二种方法更好。如果这个atomicReference.compareAndSet 失败,则意味着atomicReference 已更改,您正在读取设置的新值并检查这个新值是否有效,必要时重复。

以上是关于如何像 CAS 一样“原子地验证和延迟交换”?的主要内容,如果未能解决你的问题,请参考以下文章

CAS讲解

06 CAS的原理和AQS

像 PTLsim 这样的 CAS 模拟器如何实现 x86 硬件的周期精确模拟?

单点登录CAS使用记:实现自定义验证用户登录

与 CAS(比较和交换)相比,LL/SC 的优势是啥?

CAS(Compare and swap)比较并交换算法解析