读写锁
ReentrantReadWriteLock提供读和写分离的锁机制 WriteLock ReadLock
当读线程获取锁时,允许其他线程获取锁,阻塞写线程。
当写线程获取锁时,阻塞所有其他线程。
读写都支持线程重入机制。
锁状态采用按位分割的方式表示读写状态和重入次数。
高16位表示读状态。在获取c == state之后,按位右移16位c>>>16获取读状态。读状态增加时,按位左移增加。state = c + addCount<<16.
写锁状态为c&Ox0000FFFF,写锁状态增加时 直接增加state = c + addCount;
写锁获取方法源码解读
writeLock方法调用独占式获取同步状态的方法 表示写锁独占
public void lock() {
sync.acquire(1);
}
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
// 获取当前线程状态值
int c = getState();
// 按位与获取写锁状态
int w = exclusiveCount(c);
if (c != 0) {
// 如果锁状态不为0 表示有线程持有该锁
// (Note: if c != 0 and w == 0 then shared count != 0)
// 如果写锁状态为0 表示是读锁被获取 不可获取写锁 如果持有写锁的线程不是当前线程 不可获取写锁
if (w == 0 || current != getExclusiveOwnerThread())
return false;
// 判断是不是达到最大获取状态
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
// 不存在读锁 且 持有锁的线程位当前线程 允许重入 此时只有一个线程操作同步状态 无需使用CAS原子操作
setState(c + acquires);
return true;
}
// 如果当前锁状态为0 表示未有线程持有锁 该线程处于头结点可以去尝试获取锁
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
// 写锁释放源码阅读
protected final boolean tryRelease(int releases) {
// 独占式的写锁释放 判断持有锁的线程是不是当前线程
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
// 重入式锁多次释放 直到同步状态为0
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0;
if (free)
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}
// 获取读锁通过共享式的获取同步状态来获取
public void lock() {
sync.acquireShared(1);
}
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
// 获取当前锁状态
int c = getState();
// exclusiveCount(c)获取写锁状态 如果不为0 并且持有锁的线程不是当前线程 获取失败
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
// 获取读锁状态 r
int r = sharedCount(c);
// 如果允许获取读锁 且 读锁状态未达到最大值 且设置新state值成功 则获取成功
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
if (r == 0) {
// 如果原本无读锁 则设置当前线程为firstReader firstReaderHoldCount=1
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
// firstReader读锁为当前锁 添加进入次数
firstReaderHoldCount++;
} else {
//
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;
}
return fullTryAcquireShared(current);
}
锁升级和锁降级
读写锁支持锁降级 不支持锁升级 因为写锁是独占式的 排斥其他所有读锁和写锁 包含自己获取的读锁
/**
* 锁升级 不支持
*/
public static void readAndWriter(){
try{
readLock.lock();
System.out.println(Thread.currentThread().getName()+" get readLock");
try{
Thread.sleep(10000);
// 读锁被自己获取了 获取写锁也会等待
writeLock.lock();
System.out.println(Thread.currentThread().getName()+" get writeLock");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readLock.unlock();
System.out.println(Thread.currentThread().getName()+" release readLock");
}
}finally {
writeLock.unlock();
System.out.println(Thread.currentThread().getName()+" writeLock readLock");
}
}
输出结果:
Thread-0 get readLock
表明一个线程先获取读锁在获取写锁时,写锁获取会阻塞。
/**
* 锁降级 支持的
*/
public static void writeAndRead(){
try{
writeLock.lock();
System.out.println(Thread.currentThread().getName()+" get writeLock");
try{
// 写锁被自己获取 还能够获取读锁
readLock.lock();
System.out.println(Thread.currentThread().getName()+" get readLock");
}finally {
writeLock.unlock();
System.out.println(Thread.currentThread().getName()+" release writeLock");
}
}finally {
readLock.unlock();
System.out.println(Thread.currentThread().getName()+" release readLock");
}
}
输出结果:
Thread-0 get writeLock
Thread-0 get readLock
Thread-0 release writeLock
Thread-0 release readLock
一个线程写锁获取成功之后还是能够获取读锁的