整体概况
ReentrantReadWriteLock实现的是ReadWriteLock接口,没有实现Lock接口,所以ReentrantReadWriteLock本身本部具备锁的功能,必须通过调用方法readLock和writeLock获取代表读操作的读锁和代表写操作的写锁。ReentrantReadWriteLock比较适合用于读多写少的场景,可以支持并发读和排他写。
线程进入读锁的前提条件:
a)没有其他线程持有写锁,
b)没有写请求或者有写请求,但调用线程和持有锁的线程是同一个。
线程进入写锁的前提条件:
a)没有其他线程持有读锁
b)没有其他线程持有写锁
读写锁三个重要的特性:
a)公平选择性:支持非公平(默认)和公平的锁获取方式,吞吐量还是非公平优于公平。
b)重入性:读锁和写锁都支持线程重进入。
c)锁降级:遵循获取写锁、获取读锁再释放写锁的次序,写锁能够降级成为读锁。

ReentrantReadWriteLock内部类
ReentrantReadWriteLock有五个内部类,它们之间的关系如下图所示:

读写状态的设计
读写锁需要在同步状态(一个整形变量)上维护多个读线程和一个写线程的状态,所以需要将整形变量通过“按位切割使用”:将变量切割成两部分,高16位表示读,低16位表示写。如下图所示:

读写锁状态操作
假设当前同步状态值为S,get和set的操作如下:
a)获取写状态:
S&0x0000FFFF:将高16位全部抹去
a)获取读状态:
S>>>16:无符号补0,右移16位
a)写状态加1:
S+1
a)读状态加1:
S+(1<<16)即S + 0x00010000
写锁加锁过程

writerShouldBlock方法体现了公平性和非公平性。公平锁需要根据队列中是否有其他线程在等待来决定是否要阻塞本次获取锁的操作,非公平锁直接返回false,不阻塞本次获取锁的操作。
写锁的解锁过程

状态变量的低16位如果为0,需要取消独占锁。
读锁加锁过程


读锁解锁过程

网友评论