我的猜测是synced关键字更糟糕,因为存在阻塞锁的风险(可能导致线程上下文切换等)
是的,在通常情况下,您是对的。Java Concurrency in
Practice在15.3.2节中对此进行了讨论:
在高竞争级别上,锁定倾向于胜过原子变量,但是在更现实的竞争级别上,原子变量胜过锁定。这是因为锁通过挂起线程来对竞争做出反应,从而减少了CPU使用率和共享内存总线上的同步流量。(这类似于在生产者-消费者设计中阻止生产者如何减轻消费者的负担,从而使他们追赶。)另一方面,利用原子变量,争用管理被推回到调用类。像大多数基于CAS的算法一样,
AtomicPseudoRandom通过立即重试对竞争做出反应,这通常是正确的方法,但在竞争激烈的环境中只会创造更多竞争。Before we condemn
AtomicPseudoRandomas poorly written or atomic variables
as a poor choice compared to locks, we should realize that the level of
contention in Figure 15.1 is unrealistically high: no real program does
nothing but contend for a lock or atomic variable. In practice, atomics tend
to scale better than locks because atomics deal more effectively with
typical contention levels.锁和原子在不同争用级别之间的性能反转说明了每种锁的优缺点。竞争程度低到中等时,原子提供了更好的可伸缩性。如果争用程度较高,则锁可以更好地避免争用。(基于CAS的算法在单CPU系统上也胜过基于锁的算法,因为CAS总是在单CPU系统上成功,除非在不太可能的情况下,在读-
修改-写操作的中间抢占了线程,这种情况除外。 )
(在文本引用的图上,图15.1显示,当争用较高时,AtomicInteger和ReentrantLock的性能大致相等,而图15.2显示,在中等争用下,前者的性能要比后者高2-3倍)
更新:非阻塞算法
正如其他人指出的那样,非阻塞算法虽然可能更快,但更复杂,因此更难正确。JCiA第15.4节的提示:
良好的非阻塞算法可用于许多常见的数据结构,包括堆栈,队列,优先级队列和哈希表,尽管设计新的非阻塞算法是专家的最佳任务。
非阻塞算法比基于锁的等效算法要复杂得多。创建非阻塞算法的关键是弄清楚如何在保持数据一致性的同时将原子更改的范围限制为单个变量。在诸如队列之类的链接收集类中,有时可以将状态转换表示为对单个链接的更改,而使用
AtomicReference来表示必须原子更新的每个链接,这有时是可以避免的。



