StampedLock实现思想StampedLock内部是基于CLH锁实现的,CLH是一种自旋锁,能够保证没有“饥饿现象”的发生,并且能够保证FIFO(先进先出)的服务顺序 。
在CLH中,锁维护一个等待线程队列,所有申请锁 , 但是没有成功的线程都会存入这个队列中 , 每一个节点代表一个线程,保存一个标记位(locked),用于判断当前线程是否已经释放锁,当locked标记位为true时 , 表示获取到锁,当locked标记位为false时,表示成功释放了锁 。
当一个线程试图获得锁时,取得等待队列的尾部节点作为其前序节点,并使用类似如下代码判断前序节点是否已经成功释放锁:
while (pred.locked) { //省略操作}只要前序节点(pred)没有释放锁,则表示当前线程还不能继续执行 , 因此会自旋等待;反之,如果前序线程已经释放锁,则当前线程可以继续执行 。
释放锁时,也遵循这个逻辑,线程会将自身节点的locked位置标记为false,后续等待的线程就能继续执行了,也就是已经释放了锁 。
StampedLock的实现思想总体来说,还是比较简单的 , 这里就不展开讲了 。
StampedLock的注意事项在读多写少的高并发环境下,StampedLock的性能确实不错,但是它不能够完全取代ReadWriteLock 。在使用的时候,也需要特别注意以下几个方面 。
StampedLock不支持重入没错 , StampedLock是不支持重入的 , 也就是说,在使用StampedLock时,不能嵌套使用,这点在使用时要特别注意 。
StampedLock不支持条件变量第二个需要注意的是就是StampedLock不支持条件变量,无论是读锁还是写锁,都不支持条件变量 。
StampedLock使用不当会导致CPU飙升这点也是最重要的一点,在使用时需要特别注意:如果某个线程阻塞在StampedLock的readLock()或者writeLock()方法上时,此时调用阻塞线程的interrupt()方法中断线程 , 会导致CPU飙升到100% 。例如 , 下面的代码所示 。
public void testStampedLock() throws Exception{ final StampedLock lock = new StampedLock(); Thread thread01 = new Thread(()->{ // 获取写锁 lock.writeLock(); // 永远阻塞在此处 , 不释放写锁 LockSupport.park(); });thread01.start(); // 保证thread01获取写锁 Thread.sleep(100); Thread thread02 = new Thread(()-> //阻塞在悲观读锁 lock.readLock() );thread02.start(); // 保证T2阻塞在读锁 Thread.sleep(100); //中断线程thread02 //会导致线程thread02所在CPU飙升thread02.interrupt();thread02.join();}运行上面的程序,会导致thread02线程所在的CPU飙升到100% 。
这里,有很多小伙伴不太明白为啥LockSupport.park();会导致thread01会永远阻塞 。这里 , 冰河为你画了一张线程的生命周期图,如下所示 。
文章插图
这下明白了吧?在线程的生命周期中,有几个重要的状态需要说明一下 。
- NEW:初始状态 , 线程被构建 , 但是还没有调用start()方法 。
- RUNNABLE:可运行状态,可运行状态可以包括:运行中状态和就绪状态 。
- BLOCKED:阻塞状态 , 处于这个状态的线程需要等待其他线程释放锁或者等待进入synchronized 。
- WAITING:表示等待状态,处于该状态的线程需要等待其他线程对其进行通知或中断等操作,进而进入下一个状态 。
- TIME_WAITING:超时等待状态 。可以在一定的时间自行返回 。
- TERMINATED:终止状态,当前线程执行完毕 。
所以 , 在使用StampedLock时 , 一定要注意避免线程所在的CPU飙升的问题 。那如何避免呢?
那就是使用StampedLock的readLock()方法或者读锁和使用writeLock()方法获取写锁时,一定不要调用线程的中断方法来中断线程,如果不可避免的要中断线程的话 , 一定要用StampedLock的readLockInterruptibly()方法获取可中断的读锁和使用StampedLock的writeLockInterruptibly()方法获取可中断的悲观写锁 。
最后,对于StampedLock的使用,JDK官方给出的StampedLock示例本身就是一个最佳实践了,小伙伴们可以多看看JDK官方给出的StampedLock示例,多多体会下StampedLock的使用方式和背后原理与核心思想 。
点击关注 , 第一时间了解华为云新鲜技术~
【StampedLock:一个并发编程中非常重要的票据锁】
推荐阅读
- .NET 7 RC 2 发布,倒计时一个月发布正式版
- Java 最长公共前缀
- 王者荣耀金秋印记一个如何获取
- .NET平台下一个你不知道的框架,我只想说两个字:“牛逼”
- Go Micro介绍与入门
- 快手直播怎么只让一个人看(快手在哪里看直播回放)
- 阿姆斯特丹机场u002F史基浦机场 退税攻略 阿姆斯特丹是中国到欧洲的一个重要的转乘站
- 完 golang开发:go并发的建议
- 笔仙怎么玩……一个人又该怎么玩(笔仙的步骤)
- 一个对讲机可以怎么玩(对讲机一个人怎么玩)