前面一篇已经分析了针对读多写少的安全并发读写的场景,但是如果写相对较多时,对读是互斥的。为了进一步提升读写锁(ReentrantReadWriteLock)的性能,加上乐观锁的思想那么StampedLock就产生了。主要的改变就是从悲观读调整为乐观读,乐观则需要增加版本号【很多方法的版本号为0表示没有或者到锁,或者执行失败】,所有相关方法都会体现。StrampedLock的特点:
ReadWriteLock的子集
public class StampedLock implements java.io.Serializable {
transient StampedLock.ReadLockView readLockView;
transient StampedLock.WriteLockView writeLockView;
transient StampedLock.ReadWriteLockView readWriteLockView;
final class ReadLockView implements Lock {
}
final class WriteLockView implements Lock {
}
final class ReadWriteLockView implements ReadWriteLock {
public Lock readLock() { return asReadLock(); }
public Lock writeLock() { return asWriteLock(); }
}
}
StrampedLock不支持重入
StampedLock的悲观读锁,写锁都不支持条件变量
final class ReadLockView implements Lock {
public Condition newCondition() {
throw new UnsupportedOperationException();
}
}
final class WriteLockView implements Lock {
public Condition newCondition() {
throw new UnsupportedOperationException();
}
}
支持所的升级和降级【慎用:tryConvertToReadLock、tryConvertToWriteLock】
需要支持interrupt的调用方法【readLockInterruptibly、writeLockInterruptibly】
读写锁方法调用需要注意,不能调用interrupt,否则可能照成CPU飙升至100%
/**
* 使用{@link StampedLock} 时候直接调用 {@link Thread#interrupt()} 会照成CPU 100%
*
* @author kevin
* @date 2020/7/31 23:26
* @since 1.0.0
*/
public class StampedLockUserInterruptCpu100 {
public static void main(String[] args) throws InterruptedException {
new StampedLockUserInterruptCpu100().cpu100Percent();
}
private void cpu100Percent() throws InterruptedException {
final StampedLock stampedLock = new StampedLock();
Thread thread = new Thread(() -> {
// 获取写锁
stampedLock.writeLock();
// 模拟任务永远阻塞,则需要调用线程的interrupt
LockSupport.park();
});
thread.start();
// 为保证thread获取写锁,休眠
Thread.sleep(100);
Thread thread2 = new Thread(() -> {
// 阻塞在悲观读
stampedLock.readLock();
});
thread2.start();
// 保证thread2 阻塞在读锁
Thread.sleep(100);
// 中断thread2 线程, 会导致所在线程的CPU飙升
thread2.interrupt();
thread2.join();
}
}