比较交换和阻塞算法之间的性能比较



我有一个ConcurrentLinkedQueue,用作底层数据结构。在每次put调用中,我都会向列表中添加一个唯一的递增值。我有这个方法的同步、比较和交换版本。当我有几个线程(例如,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

TL;DR,因为在不受控制的情况下,JVM将优化synchronized并将其替换为CAS锁。

在您的CAS案例中,您有开销:即使CAS失败,您也要尝试进行一些计算。当然,与真正的互斥获取相比,这算不了什么,这通常发生在使用synchronized时。

但JVM并不愚蠢,当它看到您当前获取的锁是无争用的时,它只是用CAS锁替换真正的互斥锁(甚至在有偏见的锁的情况下用简单的存储)。因此,对于synchronized的两个线程,您只测量一个CAS,但对于您自己的CAS实现,您还测量分配Foo实例的时间,例如compareAndSet和get()。

对于2000个线程,JVM不执行CAS优化,所以您的实现的性能优于预期的获取互斥对象。

相关内容

  • 没有找到相关文章

最新更新