为什么Java StampedLock比ReentrantReadWriteLock更快

时间:2017-05-01 17:57:36

标签: java multithreading nonblocking

comparison of StampedLock and other locks表明StampedLock是竞争加剧时最快的enter image description here。然而,这篇以及其他各种文章都没有列出为什么它更快。它似乎使用与其他类型的锁相同的CAS语义?任何人都可以解释为什么争用上升最快?
例如,在此代码的下面,writeLock不仅会阻塞其他writeLocks,还会阻塞readLocks。此时我并不关心optimisticReadLocks等。只是简单的writeLock ..什么是优势,它如何比ReentrantLock更快(加上它甚至没有重入)。

    public static void main(String[]args)throws Exception{
    StampedLock lk = new StampedLock();

    new Thread(() -> {
        long stamp = lk.writeLock();
        try {
            out.println("locked.. sleeping");
            TimeUnit.SECONDS.sleep(5);
            lk.unlock(stamp);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();

    new Thread(() -> {
        long stamp = lk.writeLock();
        try {
            out.println("locked.. sleeping");
            TimeUnit.SECONDS.sleep(5);
            lk.unlock(stamp);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();

}

1 个答案:

答案 0 :(得分:2)

要明确的是,当争用增加时,StampedLock的读取速度会快得多。写作者要快一点,但不如读取速度快。我会解释原因。

大多数情况下,使用读写锁定,写入更少。但是,尽管如此,每次在readLock()上获得ReentrantReadWriteLock时,您都必须增加读者数量。这会强制使用此锁定在所有核心上进行高速缓存失效。

在严重争用下,这会导致读取时显着减慢。读取应该很快,在执行readLock()时我们不应该更新变量,这是反直觉的。

相反,如果我们有印章或让我们说版本?每次读取迭代只更新一次的一个。

在竞争中,如果只有一个线程更新了一个戳记值(比如说在写入之后),那么这对我们的影响是,当想要读取锁定时,所有读取线程都将执行缓存命中。这会禁止缓存失效,并允许锁以比RRWL更合适的方式执行。

使用StampedLock的模式类似于使用tryOptimisticRead时的无锁算法(如CAS)

  1. 获得一张邮票
  2. 读取值
  3. 邮票是否已更改?
    • 是,请再试一次或发出阻止阅读
    • 不,我们很好,让我们继续前进。