真正无锁算法的主要优点是,即使任务得到了一个任务,它们也是健壮的(请注意,无锁是比“不使用锁”(*)更难的条件)。尽管避免不必要的锁定具有性能优势,但性能最佳的数据结构通常是那些在许多情况下可以操作锁定但仍可以使用锁来最小化颠簸的数据结构。
(*)我已经看到了一些“无锁”多生产者队列的尝试,其中生产者在错误的时间获得了镶嵌,会阻止消费者在完成其工作之前看到任何新项目;这种数据结构不应该被称为“无锁”。一个被阻止的生产者不会阻止其他生产者取得进展,但可能会随意阻止消费者。
无锁算法绝对比阻塞算法更快。但当然反过来也是如此。假设实现比锁定计数器部分更好,唯一的限制因素是争用。
获取两个Java类ConcurrentLinkedQueue和LinkedBlockingQueue。在温和的现实世界争论中,CLQ的表现优于LBQ。由于争用很大,使用挂起线程将使LBQ表现更好。
我不同意user237815。 synchronized关键字不需要像以前那样多的开销,但相对于无锁算法,与单个CAS相比,它确实具有相关的大量开销。
至少在Java中,锁定本身可以非常快。 synchronized关键字不会增加很多开销。您可以通过在循环中调用synchronized方法来自己进行基准测试。
当存在争用时,锁定仅变慢,并且锁定的过程不是即时的。
最近 JavaOne俄罗斯 Oracle员工(专门研究Java性能和基准测试)在使用CAS(实际上是无锁,高级自旋锁)和经典锁(java.util.concurrent)的并行访问中显示了一些关于每秒操作的测量结果。 .locks.ReentrantLock)
http://dl.dropbox.com/u/19116634/pics/lock-free-vs-locks.png //对不起,我无法粘贴图片
据此,只有少数线程试图访问监视器,自旋锁才有更好的性能。
通常,无锁算法每个线程的效率较低 - 正如您所提到的,您正在做更多工作,以实现无锁算法而不是简单锁。
但是,它们确实倾向于在面对争用时显着提高算法的整体吞吐量。 线程切换延迟 和 上下文切换 ,快速,多线程大大减慢了应用程序的吞吐量。有效锁定算法正在实现它们自己的“锁定”,但它们以防止或减少上下文切换次数的方式这样做,这就是为什么它们倾向于执行锁定对应的原因。
话虽如此 - 大部分都取决于所讨论的算法(和实现)。例如,我有一些例程,我设法切换到.NET 4的新并发集合,而不是使用以前的锁定机制,并测量了我的总算法速度超过30%的改进。话虽这么说,但与基本锁相比,您可以找到许多使用这些相同集合的性能降低的基准测试。与所有性能优化一样 - 除非你真的不知道 测量 。
无锁不一定更快,但它可以消除死锁或活锁的可能性,因此您可以保证您的程序将始终在完成方面取得进展。有了锁,很难做出任何这样的保证 - 很容易错过导致死锁的一些可能的执行序列。
过去,这完全取决于。至少根据我的经验,速度差异往往更多地取决于实施中部署的技能水平,而不是它是否使用锁定。