Java并发:CAS与锁定

Pri*_*ine 69 java concurrency locking compare-and-swap

我正在阅读Book Java Concurrency in Practice.在第15章中,他们讨论的是非阻塞算法和比较交换(CAS)方法.

据说CAS比锁定方法表现更好.我想问那些已经使用过这两个概念的人,并希望听到你何时更喜欢这些概念中的哪一个?它真的快得多吗?

对我来说,锁的使用更清晰,更容易理解,甚至可能更好维护(如果我错了,请纠正我).我们是否应该专注于创建与CAS相关的并发代码而不是锁定以获得更好的性能提升或者可持续性更重要?

我知道在使用什么时可能没有严格的规定.但我只是想听听CAS新概念的一些看法和经验.

Mar*_*tos 41

CAS通常比锁定快得多,但它确实取决于争用程度.因为如果值在读取和比较之间变化,CAS可能会强制重试,如果有问题的变量被许多其他线程严重打击(或者计算新值很昂贵),理论上线程可能会陷入忙等待状态从旧的价值(或两者)).

CAS的主要问题是正确编程比锁定要困难得多.你要知道,锁定,反过来,更难正确使用比信息传递或STM,所以不要把这个作为对锁的使用振铃代言.

  • 我同意,强调*计算新值的费用*。往往如此之大,使得非锁策略输给了基于锁的策略。 (2认同)

小智 28

操作的相对速度在很大程度上是无问题的.相关的是基于锁定和非阻塞算法之间的可伸缩性的差异.如果您在1或2核心系统上运行,请不要再考虑这些事情了.

非阻塞算法通常更好地扩展,因为它们具有比基于锁的算法更短的"关键部分".


Joh*_*int 22

你可以看一下a ConcurrentLinkedQueue和a 之间的数字BlockingQueue.您将看到CAS在温和(在实际应用程序中更真实)线程争用下明显更快.

最吸引人的非阻塞算法的事实是,如果一个线程失败(高速缓存未命中,或者更糟的是,赛格故障),那么其他线程不会注意到这个故障,无法继续前进.但是,当获取锁定时,如果锁定保持线程有某种类型的操作系统故障,则等待锁定被释放的每个其他线程也会因故障而被命中.

要回答您的问题,是的,非阻塞线程安全算法或集合(ConcurrentLinkedQueue,ConcurrentSkipListMap/Set)可能比阻塞对应物快得多.正如Marcelo指出的那样,非阻塞算法的正确性非常困难,需要大量考虑.

您应该阅读Michael和Scott Queue,这是队列实现,ConcurrentLinkedQueue并解释了如何使用单个CAS处理双向,线程安全的原子函数.


Vic*_*kin 13

有一本与无锁并发主题密切相关的好书:Maurice Herlihy撰写的"多处理器编程艺术"


小智 8

如果您正在寻找真实的世界比较,这里有一个.我们的应用程序有两(2)个线程1)用于网络数据包捕获的读取器线程和2)接收数据包,计数和报告统计信息的消费者线程.

线程#1一次与线程#2交换单个数据包

结果#1 - 使用与SynchronousQueue相同原理的基于CAS的自定义交换,其中我们的类称为CASSynchronousQueue:

30,766,538 packets in 59.999 seconds ::  500.763Kpps, 1.115Gbps 0 drops
libpcap statistics: recv=61,251,128, drop=0(0.0%), ifdrop=0
Run Code Online (Sandbox Code Playgroud)

结果#2 - 当我们用标准的java SynchronousQueue替换CAS实现时:

8,782,647 packets in 59.999 seconds ::  142.950Kpps, 324.957Mbps 0 drops 
libpcap statistics: recv=69,955,666, drop=52,369,516(74.9%), ifdrop=0
Run Code Online (Sandbox Code Playgroud)

我不认为表现上的差异不会更清楚.