【639、ReentrantReadWriteLock 和 StampedLock】

67 阅读2分钟

ReentrantReadWriteLockStampedLock都是Java中的锁实现,它们都提供了读写分离的机制,即允许多个线程同时读取共享数据,但只允许一个线程写入共享数据。

ReentrantReadWriteLock是一个可重入的读写锁。这意味着如果一个线程已经获得了读锁或写锁,那么它可以多次获取该锁,而不会被阻塞。这种锁的好处是读操作可以同时进行,从而提高了系统的并发性能。但是,如果写锁被持有,那么读锁和写锁都会被阻塞,直到写锁被释放。ReentrantReadWriteLock可以通过readLock()writeLock()方法来获取读锁和写锁。

StampedLock也是一个读写锁,但它的实现和ReentrantReadWriteLock有所不同。StampedLock引入了一种称为“stamp”的机制,用于标记锁的状态。读取操作需要获得一个“stamp”,而写入操作需要获得一个独占锁,这与ReentrantReadWriteLock类似。不同的是,StampedLock允许读取操作在获取“stamp”后进一步进行,而不必一直持有锁。因此,当读取操作比写入操作频繁时,StampedLock可能比ReentrantReadWriteLock具有更好的性能。

需要注意的是,StampedLock在某些情况下可能会出现死锁的问题。因此,在使用StampedLock时,必须仔细考虑锁的获取和释放顺序,以避免死锁的发生。

总的来说,ReentrantReadWriteLock适用于读写操作相对平衡的场景,而StampedLock适用于读操作频繁的场景,但需要注意避免死锁的问题。

StampedLock中,stamp是一个64位的状态标记,用于标识锁的状态。在读锁被获取时,stamp的值会发生变化,这个变化可以被用来检查读取操作是否仍然有效。在写锁被获取时,stamp的值为零,因为写锁是独占的。

StampedLock中有三种获取锁的方式:readLock()用于获取读锁,返回一个stampwriteLock()用于获取写锁,返回一个零值的stamptryOptimisticRead()用于尝试获取一个乐观读锁,返回一个stamp,但不阻塞线程。如果在乐观读取期间没有发生写入,则可以使用validate(stamp)方法检查stamp是否仍然有效。如果在乐观读取期间有写入,则必须重新获取读锁或写锁。

使用StampedLock时需要注意,stamp值可能被重复使用,因此在验证stamp时必须确保stamp值不等于零,否则可能会产生错误的结果。此外,StampedLock的性能取决于锁的争用程度,如果争用程度太高,性能可能会下降。