Java 在 1.8 这个版本里,提供了一种叫 StampedLock 的锁,它的性能就比读写锁还要好。
为什么需要StampedLock
ReadWriteLock 支持两种模式:一种是读锁,一种是写锁,ReadWriteLock 支持两种模式:一种是读锁,一种是写锁。而 StampedLock 支持三种模式,分别是:写锁、悲观读锁和乐观读。
含义类似 | 含义类似 | ||
---|---|---|---|
ReadWriteLock | 写锁 | 读锁 | |
StampedLock | 写锁 | 悲观读锁 | 乐观读(性能好的关键) |
StampedLock 里的写锁和悲观读锁加锁成功之后,都会返回一个 stamp;然后解锁的时候,需要传入这个 stamp
StampedLock 提供的乐观读,是允许一个线程获取写锁的,也就是说不是所有的写操作都被阻塞。
和数据库的乐观锁异曲同工之妙
mysql中为了避免多个线程对于一行数据修改多次,用了version的思想,
stamp其实就是多版本思想体现
多版本思想在处理并发问题很常见 例如innodb中为了解决幻读引入了mvcc,java 中解决cas中的ABA问题都用到了多版本。
StampedLock 使用注意事项
- 不支持重入
- StampedLock 的悲观读锁、写锁都不支持条件变量
- 使用 StampedLock 一定不要调用中断操作,如果需要支持中断功能,一定使用可中断的悲观读锁 readLockInterruptibly() 和写锁 writeLockInterruptibly()
课后思考
```java
private double x, y; final StampedLock sl = new StampedLock(); // 存在问题的方法 void moveIfAtOrigin(double newX, double newY){ long stamp = sl.readLock(); try { while(x == 0.0 && y == 0.0){ long ws = sl.tryConvertToWriteLock(stamp); if (ws != 0L) { x = newX; y = newY; break; } else { sl.unlockRead(stamp); stamp = sl.writeLock(); } } } finally { sl.unlock(stamp); } ```
解答
在锁升级的时候没有释放写锁 解决办法:
- 把写锁的ws赋值给stamp
- 在finally中sl.unlock(ws) //需要把ws移动到外边。
mysql中执行update是什么锁?
后记
mvcc一直有俩个问题
第一是mvcc为什么是undo log版本链条?
第二是mvcc什么时候合并?在事务提交之后?