ReentrantReadWriteLock之读写锁基础
- ReentrantReadWriteLock的读锁之间是不互斥的
- ReentrantReadWriteLock的写锁之间,写锁与读锁之间是互斥的
- ReentrantReadWriteLock适用于读写并发,并且读多写少的场景
ReentrantReadWriteLock的初始化:
private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
// 读锁初始化
private static ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
// 写锁初始化
private static ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
读写锁的实现原理
ReentrantReadWriteLock是基于AQS实现的,还是对state进行操作,拿到锁资源就去干活,没有拿到,放到AQS中排队
- ReentrantReadWriteLock是可重入锁
- 读锁操作:基于state的高16位进行操作
- 写锁操作:基于state的低16位进行操作
写锁重入:
读写锁中的写锁重入方式基本和ReentrantLock一致,依然是对state进行+1操作。只要确认持有锁资源的线程是当前线程即可。只不过之前ReentrantLock的重入次数比写锁多
读锁重入:
因为读锁是共享锁,所以同一时间会有多个读锁线程持有锁资源。这样一来,无法确认每个线程读锁重入的次数。为了记录重入次数,每个读锁线程都会用ThreadLocal去记录。
写锁的饥饿问题:
读锁是共享锁,当有线程持有锁资源时,再来一个线程想要获得写锁,此时,大量想要获得读锁的线程来申请锁资源,如果可以绕过写锁直接拿到资源,会造成写锁长时间无法获得锁资源的情况
解决方式:读锁在拿到锁资源后,如果再有线程想要获得读锁资源,先判断同步队列中是否有写锁线程,如果有,需要去同步队列中排队。持有读锁的线程只会让写锁线程之前的读线程拿到锁资源