//读写锁
private ReadWriteLock lock =new ReentrantReadWriteLock();
//读锁 ————共享锁
private Lock readLock = lock.readLock();
//写锁 ————排它锁
private Lock writeLock =lock.writeLock();
ReentrantReadWriteLock类实现 ReadWriteLock接口,其中ReadLock类和WriteLock类都实现了Lock接口,都是ReentrantReadWriteLock的静态内部类。
其有一个成员属性为 final Sync sync;
在创建ReentrantReadWriteLock时创建的Sync同步器
查看源码可见,使用了this关键字,默认使用的是不公平锁。
public ReentrantReadWriteLock() {
this(false);
}
/**
*支持公平锁和不公平锁
*/
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
继承关系
---->AQS
----> Sync
---->FairSync
---->NonfairSync
//ReadLock的lock()方法,由于读锁是共享锁,使用的是共享模式
public void lock() {
sync.acquireShared(1);
}
//WriteLock中使用独享模式,是排它锁
public void lock() {
sync.acquire(1);
}
读写锁需要保存的状态:
1、写锁重入的次数
2、读锁的个数(写锁是排它锁只有一个)
3、每个读锁的重入次数
如何保存? 由于AQS类的设计目标是成为依靠单个原子 int 值来表示状态的大多数同步器的一个有用基础,int占4个字节,32位,可以分别用16位表示读锁写锁。
//写锁WriteLock的tryAcquire()方法
protected final boolean tryAcquire(int acquires) {
//获取当前线程current
Thread current = Thread.currentThread();
//获取状态int值
int c = getState();
//The lower one representing the exclusive (writer) lock hold count,and the upper the shared (reader) hold count.(低位存读锁个数,高位存写锁个数)
//w为写锁重入次数
int w = exclusiveCount(c);
//若c不为0,则是重入锁
if (c != 0) {
// (Note: if c != 0 and w == 0 then shared count != 0)
if (w == 0 || current != getExclusiveOwnerThread())
return false;
//写锁重入次数+1>最大值(1 << 16 - 1 即 1左移16位减一为65535,写锁支持重入次数)
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 重入成功,状态值+1,返回true
setState(c + acquires);
return true;
}
/**查看NonfairSync源码writerShouldBlock永远为false
*
* final boolean writerShouldBlock() {
* return false; // writers can always barge
* }
*/
//acquires实际上是1
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
//设置c不成功返回false
return false;
//设置c成功,把持锁线程设置为当前线程,返回true
setExclusiveOwnerThread(current);
return true;
}
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0;
if (free)
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}
//当有读线程时,执行tryAcquireShared返回true,当有写线程时,执行tryAcquireShared返回false
//记录读锁重入次数
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState();
//独占锁不为0(存在写线程) 且 独占线程不是当前线程 返回-1(取不到)
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
int r = sharedCount(c);
//无读阻塞 且 小于最大值 且设置成功
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
//r=0表示第一个线程
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
}
//当前线程重入,int值自增
else if (firstReader == current) {
firstReaderHoldCount++;
}
//有另外线程进入竞争
else {
//HoldCounter类记录了重入次数和线程id
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
}
return 1;
}
//使用for(;;)死循环重复执行上述代码,直到返回-1或1结果
return fullTryAcquireShared(current);
}
//读锁WriteLock的tryReleaseShared()
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
//第一个读锁线程等于当前线程
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
int count = rh.count;
if (count <= 1) {
readHolds.remove();
if (count <= 0)
throw unmatchedUnlockException();
}
--rh.count;
}
for (;;) {
int c = getState();
int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc))
// Releasing the read lock has no effect on readers,
// but it may allow waiting writers to proceed if
// both read and write locks are now free.
return nextc == 0;
}
}
private Map map = new HashMap();
//读写锁
private ReadWriteLock lock =new ReentrantReadWriteLock();
//读锁
private Lock readLock = lock.readLock();
//写锁
private Lock writeLock =lock.writeLock();
private volatile boolean flag;
public void readwrite() {
//为了保证flag能拿到最新的值
readLock.lock();
if(flag) {
//对值进行写操作,因为读写锁互斥,若不释放读锁,则写锁无法获取
readLock.unlock();
//获取写锁 读锁释放完毕后,所有写锁竞争线程
writeLock.lock();
//写锁是排它锁,最终有一个线程获得写锁,并执行put写操作
map.put("hello", "hi");
//在写完后,若不加读锁,则直接释放读锁,其他线程可能同样进行put()写操作
//在此加了读锁后,读写锁是互斥的,其他线程必须等待readLock读锁释放后才能写(put )成功
readLock.lock(); //获取读锁进行锁降级
//释放写锁
writeLock.unlock();
}
Object value = map.get("hello");
System.out.println(value);
readLock.unlock();
}