Java 比较、交换和阻塞算法的性能比较
我有一个Java 比较、交换和阻塞算法的性能比较,java,concurrency,blocking,lock-free,Java,Concurrency,Blocking,Lock Free,我有一个ConcurrentLinkedQueue,用作底层数据结构。每次put调用时,我都会向列表中添加一个唯一的递增值。我有这个方法的synchronized和compare-and-swap版本。当我只有很少的线程(例如,5个)并且总共做了1000万次put时,我发现同步版本工作得更好。当我有多个线程(例如,2000个)并且总共执行相同数量的put时,我发现CAS工作得更好。为什么CAS的性能不如线程较少的阻塞算法 // AtomicReference<Foo> latestV
ConcurrentLinkedQueue
,用作底层数据结构。每次put调用时,我都会向列表中添加一个唯一的递增值。我有这个方法的synchronized和compare-and-swap版本。当我只有很少的线程(例如,5个)并且总共做了1000万次put时,我发现同步版本工作得更好。当我有多个线程(例如,2000个)并且总共执行相同数量的put时,我发现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;
}
}
}
TL;DR因为在无竞争的情况下,JVM将优化
synchronized
,并用CAS锁替换它
在您的CAS案例中,您得到了开销:您正在尝试进行一些计算,即使您的CAS将失败。当然,与真正的互斥体获取相比,这算不了什么,当您使用synchronized
时通常会发生什么
但是JVM并不愚蠢,当它看到您当前获取的锁是无约束的时,它只是用CAS锁(或者在有偏差的锁定情况下,甚至用简单的存储)替换真正的互斥锁。
因此,对于synchronized
中的两个线程,您只测量了一个CAS,但对于您自己的CAS实现,您还测量了分配Foo实例的时间,例如compareAndSet和get()
对于2000个线程,JVM不执行CAS优化,因此您的实现比预期的互斥获取更出色。我认为您的观察结果是关键。@Fildor您能详细说明一下吗?如果涉及更多线程,那么无锁工作就更重要了。因为碰撞的概率会高得多。如果您只有几个线程,那么开销较小的实现可能会执行得更好,即使它包含锁定。@Fildor好的,我理解这一部分。我不明白的是,为什么当线程数较少时,CAS的性能不好。您对“坏”的定义是什么?您是如何实现CAS的?也许还有一些优化的空间?我已经为你的案例编辑了我的答案,以更好地解释它。关于JVM CAS优化,你有什么来源可以指向我吗?@user592748当然。这是官方文件,你可以在那里找到布赖恩·戈茨的一些评论。如果您对特定的实现感兴趣,可以在这里找到一些信息:在这里可以找到实际的解释:src/cpu/x86/vm/template解释器或在hotspot/src/share/vm/解释器中/
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