(1)StampedLock邮戳锁支持三种模式,分别是:写锁,读锁,乐观读。
ReentrantReadWriteLock读写锁的缺点是在读多写少的情况下,写线程会被阻塞,写线程可能会一直抢不到锁发生饥饿现象
邮戳锁可以避免这种情况,在乐观读的时候,不会对其他的写线程阻塞,其他的线程可以获取到写锁
(2)邮戳锁的乐观读可以升级为写锁,读写锁不能由读锁升级为写锁
class Point { // 成员变量 private double x, y; // 锁实例 private final StampedLock sl = new StampedLock(); // 排它锁-写锁(writeLock) void move(double deltaX, double deltaY) { long stamp = sl.writeLock(); try { x += deltaX; y += deltaY; } finally { sl.unlockWrite(stamp); } } // 一个只读方法 // 其中存在乐观读锁到悲观读锁的转换 double distanceFromOrigin() { // 尝试获取乐观读锁 long stamp = sl.tryOptimisticRead(); // 将全部变量拷贝到方法体栈内 double currentX = x, currentY = y; // 检查在获取到读锁stamp后,锁有没被其他写线程抢占 if (!sl.validate(stamp)) { // 如果被抢占则获取一个共享读锁(悲观获取) stamp = sl.readLock(); try { // 将全部变量拷贝到方法体栈内 currentX = x; currentY = y; } finally { // 释放共享读锁 sl.unlockRead(stamp); } } // 返回计算结果 return Math.sqrt(currentX * currentX + currentY * currentY); } // 获取读锁,并尝试转换为写锁 void moveIfAtOrigin(double newX, double newY) { long stamp = sl.tryOptimisticRead(); try { // 如果当前点在原点则移动 while (x == 0.0 && y == 0.0) { // 尝试将获取的读锁升级为写锁 long ws = sl.tryConvertToWriteLock(stamp); // 升级成功,则更新stamp,并设置坐标值,然后退出循环 if (ws != 0L) { stamp = ws; x = newX; y = newY; break; } else { // 读锁升级写锁失败则释放读锁,显示获取独占写锁,然后循环重试 sl.unlockRead(stamp); stamp = sl.writeLock(); } } } finally { sl.unlock(stamp); } } }