读多写少的场景下,竟然还有比读写锁更牛X的锁?
2022/3/29 23:27:56
本文主要是介绍读多写少的场景下,竟然还有比读写锁更牛X的锁?,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1)上一篇文章我们聊了读写锁,他的适用场景是读多写少的场景下,那有没有其它性能比读写锁还要牛逼的锁呢?
-
StampedLock ,java1.8诞生的。
2)StampedLock比读写锁牛在什么地方?
-
读写锁分为两种:读锁和写锁
-
StampedLock有三种模式:写锁和悲观读锁,这两个对应我们的读写锁的写锁和读锁,功能是一样的。但是他的杀手锏是乐观读,注意是乐观读,不是乐观读锁。
-
乐观读是一种操作,不涉及到锁。当多个线程在读的时候,允许一个线程获取读锁,这个就是StampedLock与读写锁不同的地方。因为不涉及到锁,所以为了保障并发安全,会有一个stamp来作为安全的标志。类似于我们数据库乐观锁的version。
3)写锁和悲观读锁与我们读写锁的细致区别是什么?
-
他两加锁的时候会返回一个stamp,然后要解锁的话,需要带着这个stamp来。
final StampedLock sl = new StampedLock(); // 获取/释放悲观读锁示意代码 long stamp = sl.readLock(); try { //省略业务相关代码 } finally { sl.unlockRead(stamp); } // 获取/释放写锁示意代码 long stamp = sl.writeLock(); try { //省略业务相关代码 } finally { sl.unlockWrite(stamp); }
4)乐观读是怎样使用的?
-
tryOptimisticRead()就是乐观读,因为是无锁的,所所以共享变量 x 和 y 读入方法局部变量时,x 和 y 有可能被其他线程修改了。因此最后读完之后,还需要再次验证一下是否存在写操作,这个验证操作是通过调用 validate(stamp) 来实现的。
class Point { private int x, y; final StampedLock sl = new StampedLock(); //计算到原点的距离 int distanceFromOrigin() { // 乐观读 long stamp = sl.tryOptimisticRead(); // 读入局部变量, // 读的过程数据可能被修改 int curX = x, curY = y; //判断执行读操作期间, //是否存在写操作,如果存在, //则sl.validate返回false if (!sl.validate(stamp)){ // 升级为悲观读锁 stamp = sl.readLock(); try { curX = x; curY = y; } finally { //释放悲观读锁 sl.unlockRead(stamp); } } return Math.sqrt( curX * curX + curY * curY); } }
-
上面的代码中,如果乐观读的时候,存在写操作,那么就把它升级为悲观读锁。这样就避免了乐观读一直循环浪费大量的cpu,使用的时候尽量这样去做。
5)StampedLock有哪些注意事项?
-
千万不要在线程阻塞在 StampedLock 的 readLock() 或者 writeLock() 上时调用该阻塞线程的interrupt()方法,会导致运行这个线程的cpu挂掉的。如果实在要用中断方法,那就用带interrupt的悲观读锁 readLockInterruptibly() 和写锁 writeLockInterruptibly()。
final StampedLock lock = new StampedLock(); Thread T1 = new Thread(()->{ // 获取写锁 lock.writeLock(); // 永远阻塞在此处,不释放写锁 LockSupport.park(); }); T1.start(); // 保证T1获取写锁 Thread.sleep(100); Thread T2 = new Thread(()-> //阻塞在悲观读锁 lock.readLock() ); T2.start(); // 保证T2阻塞在读锁 Thread.sleep(100); //中断线程T2 //会导致线程T2所在CPU飙升 T2.interrupt(); T2.join();
-
StampedLock的功能是不如读写锁的那么多的
-
StampedLock是不支持嵌套使用的,也就是可重入锁。
6)以后有用到StampedLock的需求的时候,使用的模板应该是怎样的?
StampedLock 读模板:
final StampedLock sl = new StampedLock(); // 乐观读 long stamp = sl.tryOptimisticRead(); // 读入方法局部变量 ...... // 校验stamp if (!sl.validate(stamp)){ // 升级为悲观读锁 stamp = sl.readLock(); try { // 读入方法局部变量 ..... } finally { //释放悲观读锁 sl.unlockRead(stamp); } } //使用方法局部变量执行业务操作 ......
StampedLock 写模板:
long stamp = sl.writeLock(); try { // 写共享变量 ...... } finally { sl.unlockWrite(stamp); }
这篇关于读多写少的场景下,竟然还有比读写锁更牛X的锁?的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南