读写锁ReentrantReadWriteLock
2023-07-03 11:48:51 2 举报
读写锁ReentrantReadWriteLock入门底层原理
作者其他创作
大纲/内容
读写锁:在对共享资源读多写少的场景下,读写锁有着比ReentrantLock更快的速度
<b><font color="#b71c1c">ReentrantReadWriteLock</font></b>
线程<b>进入读锁</b>的前提条件:
没有其他线程的写锁
没有写请求或者有写请求,但是调用线程和<b>持有写锁</b>的线程是同一个
线程<b>进入写锁</b>的前提条件:
没有其他线程的读锁
没有其他线程的写锁
<b><font color="#b71c1c">应用场景:</font></b>
<b>读多写少:ReentrantReadWriteLock适用于读操作比写操作多的场景</b>
<b><font color="#b71c1c">缓存:ReentrantLockReadWriteLock实现缓存不仅可以有效的处理的大量的读操作,同时也能保证缓存数据的一致性</font></b>
<b>读写锁的三个重要的特性:</b>
<b><font color="#b71c1c">公平选择性:</font></b>支持非公平(默认)和公平锁的获取方式,吞吐量还是非公平优于公平
<b><font color="#b71c1c">可重入:</font></b>读锁和写锁都支持线程重入,读线程获取读锁之后,能够再次获取读锁。写线程在获取写锁之后能够再次获取写锁,<b>同时也能获取读锁</b>
<b><font color="#b71c1c">锁降级:</font></b>遵循获取写锁,再获取读锁最后释放写锁的次序,写锁能够降级成为读锁
<b>读写锁的设计思路</b>
<b><font color="#b71c1c">读写状态的设计:如何使用一个变量维护多种状态</font></b>
想用AQS的state变量来同时表示读和写的状态可以将变量按位切割使用<b><font color="#b71c1c">,高16位表示读。低16位表示写</font></b>
<b>写状态:</b>等于S&0x0000FFFF(将16位全部抹去)。当写状态加一,等于S+1
<b>读状态:</b>等于是>>>16(无符号补0 右移16位) 当读状态加1,等于S+(1<<<16)
<b><font color="#b71c1c">根据状态判断:</font>S不等于0时</b>,当写状态(S&0x0000FFFF)<b><font color="#b71c1c">等于</font></b>0时,则<b>读状态(S>>>16)<font color="#b71c1c">大于</font>0</b>,及读锁被获取
<b>HoldCounter计数器</b>
读锁的内在机制是一个共享锁,一次共享锁的操作就相当于对HoldCounter计数器的操作,获取共享锁则技术器加一,释放共享锁则减一。只有当线程获取共享锁后才能对共享锁进行释放,重入操作。
通过ThreadLocalHoldCounter类,HoldCounter与线程进行绑定。HoldCounter是绑定线程的<b>一个计数器</b>,而ThreadLocalHoldCounter则是线程绑定的ThreadLocal
HoldCounter是用来记录读锁重入数的对象。
<b><font color="#b71c1c">ThreadLocalHoldCounter是ThreadLocal 的变量</font></b>,用来存放不是第一个获取读锁的线程的其他线程的读锁重入对象
<b><font color="#b71c1c">StampedLock介绍</font></b>
ReentrantReadWriteLock的读锁是悲观锁,如果有线程正在读,写线程需要等待读线程释放锁后才能获取锁。
与ReentrantReadWriteLock相比,改进之处在于:读的过程中也允许获取写锁后写入!增加了乐观读的模式(Optimistic Reading)。这个模式不会加锁,不会阻塞线程,会有更高的吞吐量和更高的性能
<b><font color="#b71c1c">StampLock的三种访问模式:</font></b>
<b>Writing(独占写锁):</b>writeLock方法会使线程阻塞等待独占访问,同一时刻只有一个写线程获取锁资源
<b>Reading(悲观读锁):</b>readLock方法,允许多个线程同时获取悲观读锁,悲观读锁与独占写锁互斥,与乐观读共享
<b>Optimistic Reading(乐观读):</b><font color="#b71c1c">乐观读没有加锁</font>,不会阻塞,仅仅在当前未处于Writing模式TryOotimistic才会返回非0 的Stamp,<font color="#b71c1c">如果在获取乐观读之后没有出现写模式线程获取锁,则在方法validate返回true,允许多个线程获取乐观锁以及读锁,同时允许一个写线程获取写锁。</font>
<b><font color="#b71c1c">使用场景和注意事项:</font></b>
StampedLock<b><font color="#b71c1c">写锁是不可重入</font></b>的,同一个线程重复获取写锁会死锁
悲观读和写锁都<b>不支持</b>条件变量<b><font color="#b71c1c">Condition</font></b>
如果线程阻塞在 StampedLock 的 <b>readLock()</b> 或者<b> writeLock()</b> 上时,此时调用该阻塞线程的<b> interrupt() </b>方法,会导致 CPU 飙升。所以,使用 StampedLock 一定<b>不要调用中断操作</b>,如果需要支持中断功能,一定使用可中断的<b><font color="#b71c1c">悲观读锁 readLockInterruptibly() 和写锁 writeLockInterruptibly()</font></b>。<br><br>
0 条评论
下一页