我有ConcurrentLinkedQueue
我用作基础数据结构。在每次看涨期权中,我都会向列表中添加一个唯一的递增值。我有这个方法的synchronized和compare-and-swap版本。当我有几个线程(例如,5个)并完成1000万次放入时,我看到同步版本的效果要好得多。当我有很多线程(例如,2000)并且总共执行相同数量的放置时,我看到CAS工作得更好。与具有较少线程的阻塞算法相比,为什么CAS表现不佳?
// AtomicReference<Foo> latestValue that is initialized
public void put(Double value) {
Foo currentValue;
while (true) {
currentValue = latestValue.get();
Foo newValue = new Foo(value);
if (latestValue.compareAndSet(currentValue, newValue)) {
historyList.add(newValue);
return;
}
}
}
统计
NON-BLOCKING
Threads 2000
Puts per thread 10000
Put time average 208493309
BLOCKING
Threads 2000
Puts per thread 10000
Put time average 2370823534
NON-BLOCKING
Threads 2
Puts per thread 10000000
Put time average 13117487385
BLOCKING
Threads 2
Puts per thread 10000000
Put time average 4201127857
答案 0 :(得分:3)
TL; DR ,因为在非竞争情况下,JVM将优化synchronized
并将其替换为CAS锁。
在您的CAS案例中,您有开销:即使您的CAS失败,您也会尝试进行一些计算。当然,与真正的互斥量获取相比,它没什么用,当您使用synchronized
时通常会发生这种情况。
但是JVM并不是愚蠢的,当它看到你当前正在获取的锁是没有意义的时候,它只是用CAS锁替换真正的互斥锁(或者在有偏向锁定的情况下用简单的存储替换)。
因此,对于synchronized
情况下的两个线程,您只测量CAS,但是在您自己的CAS实现的情况下,您还要测量分配Foo实例的时间,compareAndSet和get()。
对于2000个线程,JVM不执行CAS优化,因此您的实现优于预期的互斥锁获取。