compare-and-swap和blocking算法的性能比较
Performance comparison between compare-and-swap and blocking algorithm
我有一个 ConcurrentLinkedQueue
用作底层数据结构。在每次 put 调用中,我都会向列表中添加一个唯一的增量值。我有此方法的同步版本和比较和交换版本。当我只有很少的线程(例如 5 个)并且总共执行 1000 万次输入时,我发现同步版本的效果要好得多。当我有很多线程(例如 2000)并且总共执行相同数量的 puts 时,我发现 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
TL;DR 因为在无竞争的情况下 JVM 会优化 synchronized
并用 CAS 锁替换它。
在您的 CAS 案例中,您有开销:即使您的 CAS 会失败,您仍在尝试进行一些计算。当然,与真正的互斥量获取相比,这没什么,当您使用 synchronized
.
时通常会发生什么
但是 JVM 并不愚蠢,当它看到您当前获取的锁不满足时,它只是用 CAS 锁替换真正的互斥锁(甚至在偏向锁定的情况下用简单的存储)。
因此,对于 synchronized
情况下的两个线程,您只测量一个 CAS,但在您自己的 CAS 实现的情况下,您还测量分配 Foo 实例、compareAndSet 和 get() 的时间。
对于 2000 个线程,JVM 不执行 CAS 优化,因此您的实现优于预期的互斥量获取。
我有一个 ConcurrentLinkedQueue
用作底层数据结构。在每次 put 调用中,我都会向列表中添加一个唯一的增量值。我有此方法的同步版本和比较和交换版本。当我只有很少的线程(例如 5 个)并且总共执行 1000 万次输入时,我发现同步版本的效果要好得多。当我有很多线程(例如 2000)并且总共执行相同数量的 puts 时,我发现 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
TL;DR 因为在无竞争的情况下 JVM 会优化 synchronized
并用 CAS 锁替换它。
在您的 CAS 案例中,您有开销:即使您的 CAS 会失败,您仍在尝试进行一些计算。当然,与真正的互斥量获取相比,这没什么,当您使用 synchronized
.
但是 JVM 并不愚蠢,当它看到您当前获取的锁不满足时,它只是用 CAS 锁替换真正的互斥锁(甚至在偏向锁定的情况下用简单的存储)。
因此,对于 synchronized
情况下的两个线程,您只测量一个 CAS,但在您自己的 CAS 实现的情况下,您还测量分配 Foo 实例、compareAndSet 和 get() 的时间。
对于 2000 个线程,JVM 不执行 CAS 优化,因此您的实现优于预期的互斥量获取。