编程基础: 硬件同步原语
在并发编程中,我们常常使用锁来保护共享资源,这样会导致性能上的损失。在一些情况下,可以采用硬件同步原语来替代锁,在确保数据安全性的同时,也可以获取更好的性能。
硬件同步原语(Atomic Hardware Primitives)由计算机硬件(即 CPU 提供的实现)提供的一组原子操作,较常用的原语主要是
CAS(Compare and Swap)
FAA(Fetch and And)
CAS 原语
CAS 实现的伪码:
ABA 问题
假设存在两个线程 P1 和 P2,它们都会对共享变量 A 操作,在下面的场景中变回存在 ABA 问题:
P1 从共享内存中读取了 A 当前的值
P2 开始执行,它将 A 的值修改为 B,并且在 P1 执行前又修改为 A
P1 又开始执行,它从共享内存读取到的值依然是 A,好像没有改变似的,实际上 A 编程 B 又变成 A。
针对 ABA 问题,Java 提供了AtomicStampedReference
通过控制变量的版本来实现确保 CAS 的正确性。
优缺点
CAS 可以实现高效的原子操作,却存在以下一些问题:
如果 CAS 失败,反复重试赋值方式,会比较消耗 CPU 资源。如果赋值不成功,会无等待立即进入下一轮循环,如果线程间碰撞频繁,反复重试,重试线程会占用大量的 CPU 时间。
只能保证一个共享变量的原子操作。当对一个共享变量执行操作时,我们可以使用循环 CAS 的方式来保证原子操作,但是对多个共享变量操作时,循环 CAS 就无法保证操作的原子性,这个时候就可以用锁来保证原子性。
存在 ABA 问题。
FAA 原语
FAA 伪码:
FAA 原语的操作是先获取变量的当前值,之后进行计算,更新数据。FAA 原语的计算逻辑只局限于简单的加减法,而 CAS 原语的使用范围更广。
下面是[1]给出的 Go 语言实现的 CAS 和 FAA 实现:
参考资料
版权声明: 本文为 InfoQ 作者【正向成长】的原创文章。
原文链接:【http://xie.infoq.cn/article/c2c42cebcdaacb3130b5eaa88】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论