据我所知,synchronized关键字将本地线程缓存与主内存同步。 volatile关键字基本上总是在每次访问时从主内存中读取变量。当然,访问主内存比本地线程缓存昂贵得多,因此这些操作很昂贵。但是,CAS操作使用低级硬件操作但仍必须访问主存储器。那么CAS操作如何更快?
答案 0 :(得分:2)
我认为关键因素是你所说的 - CAS机制使用低级硬件指令,允许最小的缓存刷新和争用解决。
其他两种机制(synchronization
和volatile
)使用不同的体系结构技巧,这些技巧在所有不同的体系结构中更为普遍。
有趣的引自Brian Goetz(据说)
操作的相对速度在很大程度上不是问题。相关的是基于锁的算法和非阻塞算法之间的可扩展性差异。如果您在1或2核心系统上运行,请不要再考虑这些事情了。
非阻塞算法通常可以更好地扩展,因为它们比基于锁的算法具有更短的“关键部分”。
答案 1 :(得分:1)
请注意,CAS不一定要访问内存。
大多数现代架构都实现了像MESI这样的缓存一致性协议,如果只有一个线程同时访问数据,则允许CPU执行快捷方式。在这种情况下,与传统的,不同步的内存访问相比,开销非常低。
然而,当对相同的值进行大量并发更改时,缓存确实毫无价值,并且所有操作都需要直接访问主内存。在这种情况下,同步不同CPU缓存和内存访问序列化的开销可能会导致性能显着下降(这也称为缓存乒乓),这可能与您遇到的情况一样糟甚甚至更糟基于锁的方法。
所以,不要简单地假设如果你切换到原子,你的所有问题都会消失。原子的最大优点是无锁(有人总能取得进步)或无等待(每个人都经过一定数量的步骤)实现的进度保证。但是,这通常与原始性能正交:无等待解决方案可能比基于锁的解决方案慢得多,但在某些情况下,您愿意接受这一点以获得进度保证。
答案 2 :(得分:0)
Compare and swap
(又名CAS
)(check then act
模式的一部分),它是一种 atomic 算法,可以更改一个值在多线程环境中。
该算法通常采用树形参数:
,由树形步骤组成:
如果发生故障,请更新旧值(A)并重复
当然,您可以使用synchronized
[About]监视器来实现它,但是从Java 5
您可以使用java.util.concurrent.atomic
软件包的优点,该软件包使用更快,更高效的CPU操作。例如:
AtomicBoolean
,AtomicInteger
,AtomicLong
...通过compareAndSet()
方法
在后台,它使用sun.misc.Unsafe
和本机sun.misc.Unsafe.compareAndSwapInt()
方法。
Unsafe
支持CAS
,内存分配,创建实例而无需调用构造函数...