ReentrantLock和ReentrantReadWriteLock從類的形式上看并沒有關(guān)聯(lián)宽堆,但是底層都是采用AQS的實(shí)現(xiàn)
我們知道我們JDK 的鎖都是基于AQS
而在其上面主要有讀寫鎖(即所謂的獨(dú)占鎖和非獨(dú)占鎖)
方法也只有l(wèi)ock 或者unlock
除了鎖 還有condition
這些鎖都支持可重入
公平鎖和非公平鎖的最大區(qū)別就是:非公平鎖是先嘗試獲取鎖哆窿,獲取不到在按照公平鎖的方法進(jìn)入隊(duì)列排隊(duì)獲取
鎖為什么不能升級--升級會死鎖稽物,目的也是為了數(shù)據(jù)可見性,如果讀鎖已經(jīng)被多個(gè)線程獲取加酵,其中任意線程成功獲取了寫鎖并且更新了數(shù)據(jù),這個(gè)更新對其他已經(jīng)獲取到讀鎖的線程是不可見的供屉。
當(dāng)有線程獲取讀鎖時(shí)往产,不允許再有線程獲得寫鎖
當(dāng)有線程獲得寫鎖時(shí),不允許其他線程獲得讀鎖和寫鎖
為什么要支持鎖降級
降級的過程為持有寫鎖撒犀,把持住不釋放并獲取讀鎖福压,然后再釋放寫鎖,如果釋放寫鎖再獲取讀鎖則不能稱之為鎖降級或舞。支持降級的原因是為了實(shí)現(xiàn)讀寫連續(xù)荆姆,減少線程切換的開銷。如果不能降級的話映凳,A線程在對數(shù)據(jù)修改完畢后立馬釋放寫鎖胆筒,假如A線程后續(xù)緊跟一個(gè)讀的操作,在獲取讀鎖之前B線程拿到了寫鎖诈豌,由于讀寫不能并發(fā)仆救,A線程就只能阻塞
首先我們分析下ReentrantLock
獲取鎖,如果獲取不到則會一直阻塞
不會響應(yīng)中斷
readLock.lock();
嘗試獲取鎖矫渔,獲取不到就返回 不會響應(yīng)中斷
readLock.tryLock();
獲取鎖彤蔽,如果獲取不到則會一直阻塞
會響應(yīng)中斷
readLock.lockInterruptibly();
嘗試獲取鎖,獲取不到就等待一段時(shí)間 會響應(yīng)中斷
readLock.tryLock(10,TimeUnit.SECONDS);
ReentrantLock的lock源碼
public final void acquire(int arg) {
首先嘗試獲取鎖失敗庙洼,則加入等待隊(duì)列顿痪,acquireQueued返回true代表
在等待獲取鎖的過程中中斷過
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
因?yàn)橹爸袛嗪竽髟珹QS恢復(fù)了中斷標(biāo)識,這邊自我中斷下吧中斷標(biāo)識
設(shè)置為true蚁袭。這樣如果有業(yè)務(wù)邏輯需要判斷中斷標(biāo)識征懈,可以得知是否中斷過
selfInterrupt();
}
非公平鎖是先嘗試獲取鎖
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
因?yàn)槭仟?dú)占鎖
int c = getState();
當(dāng)鎖沒有被持有的時(shí)候,直接去獲取 不需要管是否有其他人在等待
if (c == 0) {
設(shè)置state
if (compareAndSetState(0, acquires)) {
設(shè)置獨(dú)占標(biāo)識的線程
setExclusiveOwnerThread(current);
return true;
}
}如果當(dāng)前線程等于獨(dú)占標(biāo)識的線程
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
更新state揩悄,如果state小于0 代表重入超過最大值了
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
獲取失敗
return false;
}
公平的獲取鎖
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
如果這個(gè)鎖還沒人獲取
if (c == 0) {
如果不存在等待隊(duì)列且設(shè)置state成功 即獲取了鎖受裹,設(shè)置獨(dú)占標(biāo)識的線程
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
重入設(shè)定
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
public final boolean hasQueuedPredecessors() {
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
h!=t 代表最少有2個(gè)元素 一個(gè)是head 一個(gè)是tail
return h != t &&
第一個(gè)如果為true 正好執(zhí)行到tail了 即s=tail節(jié)點(diǎn)
否則只要判斷下s.thread不等于當(dāng)前線程
((s = h.next) == null || s.thread != Thread.currentThread());
}
按照鎖的模式把當(dāng)前線程包裝成節(jié)點(diǎn)
注意初始化之后head和老的tail節(jié)點(diǎn)的next都是第一個(gè)正常節(jié)點(diǎn),也就是新的tail節(jié)點(diǎn)
而不是新的head-->old tail-->新的tail 真正的是head-->新的tail 和old tail-->新的tail
其中head和oldtail 是同一個(gè)對象的兩種不同的引用 也就是說最終就是head-->tail tail是正常節(jié)點(diǎn)
head是dummpy節(jié)點(diǎn)
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
首先利用cas直接放入尾部
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
for循環(huán)利用cas放入隊(duì)列
enq(node);
return node;
}
這邊將tail賦值給t非常好虏束,當(dāng)我們將node設(shè)置尾部tail成功時(shí)候
t還是只想tail前一個(gè)繼續(xù)操作next綁定node棉饶,就算這個(gè)時(shí)候并發(fā)另外一個(gè)線程很快
也設(shè)置tail成功也不影響前面的設(shè)置
當(dāng)head=tail說明剛初始化好
private Node enq(final Node node) {
for (;;) {
獲取尾部
Node t = tail;
如果尾部不存在,說明還沒初始化镇匀,先初始化隊(duì)列
if (t == null) { // Must initialize
設(shè)置head節(jié)點(diǎn) 如果成功了就把head和tail 賦值為一個(gè)new出來的node節(jié)點(diǎn),然后在重新循環(huán)將該隊(duì)列設(shè)置到尾部照藻,剛初始化的節(jié)點(diǎn)是沒用的后期都會移除
if (compareAndSetHead(new Node()))
tail = head;
} else {
嘗試把節(jié)點(diǎn)加入尾部,這邊存在 pre一致 但是原始的tail的next 還是null的情況
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
循環(huán)等待該node獲取鎖汗侵,并記錄自己被中斷
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
獲取node的前置節(jié)點(diǎn)幸缕,前置節(jié)點(diǎn)有可能是正常的node
也有可能是head和tail 這種剛初始化dummpy節(jié)點(diǎn)
final Node p = node.predecessor();
如果前置節(jié)點(diǎn)就是head,那么就嘗試獲取下鎖(這時(shí)候程序在運(yùn)行的情況分為
剛加入隊(duì)列晰韵,或者被head節(jié)點(diǎn)喚醒且正在釋放鎖或者還未釋放完)
if (p == head && tryAcquire(arg)) {
獲取鎖成功把這個(gè)node設(shè)置為head
setHead(node);
p.next = null; // help GC
failed = false;
返回
return interrupted;
}
如果p不等head 或者獲取鎖失敗发乔,
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
執(zhí)行到這一步且failed=true 代表發(fā)送了異常,取消獲取
if (failed)
cancelAcquire(node);
}
}
waitStatus四種狀態(tài)
SIGNAL:標(biāo)識這個(gè)節(jié)點(diǎn)如果后期獲取到鎖 在釋放的時(shí)候需要喚醒他的后繼節(jié)點(diǎn)
CANCELLED:因?yàn)槌瑫r(shí)或者被中斷雪猪,其線程不會再阻塞
CONDITION:這個(gè)還記得咱們的Condition這個(gè)對象嗎栏尚?這個(gè)代表節(jié)點(diǎn)還在condition隊(duì)列中 還未進(jìn)入咱們的同步隊(duì)列
PROPAGATE:調(diào)用共享鎖的時(shí)候的是否應(yīng)該無條件的傳播
head節(jié)點(diǎn)就是signal其后面的正常節(jié)點(diǎn)就是condition
0:剛創(chuàng)建的節(jié)點(diǎn)都是0,這個(gè)方法就是把所以的0都轉(zhuǎn)換為signal
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
假如是剛初始化的時(shí)候 那么head的waitstatus是0
int ws = pred.waitStatus;
當(dāng)SIGNAL時(shí)候代表head節(jié)點(diǎn)正在持有鎖 還沒釋放鎖 所以后置節(jié)點(diǎn)應(yīng)該沉睡
等待head把他喚起
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
如果大于0說明節(jié)點(diǎn)是被取消的 應(yīng)該移除這些節(jié)點(diǎn)
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
這邊有個(gè)問題 pre這個(gè)廢棄節(jié)點(diǎn)如果想完全移除出鏈表
不需要 pred.next = null 因?yàn)閏ancelAcquire(node); 已經(jīng)
執(zhí)行過這段代碼了
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
一般到這一步了說明是0或者是PROPAGATE 嘗試把head節(jié)點(diǎn)設(shè)置為
SIGNAL
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
阻塞只恨,然后返回釋放interupt译仗,是的話設(shè)置interupt標(biāo)識
private final boolean parkAndCheckInterrupt() {
該線程沉睡
LockSupport.park(this);
return Thread.interrupted();
}
取消獲取失敗的節(jié)點(diǎn)
private void cancelAcquire(Node node) {
// Ignore if node doesn't exist
if (node == null)
return;
將該節(jié)點(diǎn)的thread置空
node.thread = null;
如果node的前置節(jié)點(diǎn)是取消狀態(tài),直接跳過
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
前置節(jié)點(diǎn)的next正常沒有并發(fā)的情況下就是我們的node節(jié)點(diǎn)
Node predNext = pred.next;
將節(jié)點(diǎn)狀態(tài)變?yōu)槿∠? node.waitStatus = Node.CANCELLED;
如果當(dāng)前節(jié)點(diǎn)就是tail 那么我們把tail設(shè)置為pre(pre有可能是head 也有可能是其他的節(jié)點(diǎn))
if (node == tail && compareAndSetTail(node, pred)) {
把這個(gè)節(jié)點(diǎn)的next設(shè)置為null
compareAndSetNext(pred, predNext, null);
} else {
說明不是tail
我們看看如果pre不是head 且pre是SIGNAL或者 ws<0 我們把pre的waitstatus設(shè)置為signal
且pre的thread不為空
int ws;
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
獲取node的下一個(gè)正常節(jié)點(diǎn)塞入pre的next
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
如果是head 那么我們就需要喚醒下一個(gè)節(jié)點(diǎn)
unparkSuccessor(node);
}
把脫離的節(jié)點(diǎn)從鏈表中拿出來
node.next = node; // help GC
}
}
private void unparkSuccessor(Node node) {
設(shè)置waitstatus為0官觅,因?yàn)樗南乱粋€(gè)節(jié)點(diǎn)不需要signal纵菌,我們正在signal
設(shè)置為0失敗也沒關(guān)系
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
如果節(jié)點(diǎn)的下一個(gè)是null 或者為取消狀態(tài)
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
從尾部開始尋找,node節(jié)點(diǎn)不等于當(dāng)前且waitstatus小于等于0
假如你從前往后遍歷的動作發(fā)生在enq方法中的cas之后和賦值之前最后一個(gè)節(jié)點(diǎn)是漏掉的
在enq中我們是先把新的tail的pre和老的tail 鏈接在一起 等cas成功了 在設(shè)置老tail的next和新的tail
如果我們從前往后遍歷的時(shí)間剛好發(fā)生在cas之和賦值之前 那么我們tail節(jié)將被遺漏
但是我們這邊喚醒最后一個(gè)可用的 也不用怕休涤,因?yàn)槠淝爸霉?jié)點(diǎn)不是head 所以其不會獲得鎖
但是會幫我們清理取消的節(jié)點(diǎn) 這樣就可以正常的獲取下一個(gè)節(jié)點(diǎn)進(jìn)行喚醒獲得鎖的操作
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
喚醒該線程
if (s != null)
LockSupport.unpark(s.thread);
}
lockInterruptibly
public final void acquireInterruptibly(int arg)
throws InterruptedException {
如果檢測到線程中的 拋出異常
if (Thread.interrupted())
throw new InterruptedException();
獲取線程
if (!tryAcquire(arg))
這個(gè)過程我們之前分析過至少這邊如果檢測到中斷就直接拋出
我們正常的節(jié)點(diǎn)喚醒是通過unsafe的unpark方法
doAcquireInterruptibly(arg);
}
ReentrantLock的trylock 底層默認(rèn)的是采用unfaire咱圆,我們上面已經(jīng)分析過了,獲取不到直接返回
ReentrantLock的trylock 攜帶時(shí)間的參數(shù)底層也有多種實(shí)現(xiàn) 功氨,可以響應(yīng)中斷
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}
我們主要分析下如何做到時(shí)間控制
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
計(jì)算超時(shí)時(shí)間
final long deadline = System.nanoTime() + nanosTimeout;
添加節(jié)點(diǎn)
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
開始獲取鎖
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return true;
}
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L)
return false;
如果未獲取到通過LockSupport.parkNanos來沉睡
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
ReentrantLock的unlock
public final boolean release(int arg) {
嘗試釋放節(jié)點(diǎn)
if (tryRelease(arg)) {
釋放成功的話把序苏,喚醒head節(jié)點(diǎn)的下一個(gè)
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
如果當(dāng)前線程不是獲取獨(dú)占鎖的線程 拋出異常
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
如果鎖都釋放了 則解除獨(dú)占狀態(tài)
free = true;
setExclusiveOwnerThread(null);
}
重新設(shè)置state
setState(c);
return free;
}
再分析ReentrantReadWriteLock.WriteLock
ReentrantReadWriteLock.WriteLock 的lock
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
主要是tryAcquire與reentrant不一樣我們分析下
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
當(dāng)c!=0 w=0 代表共享鎖被獲取了 但是獨(dú)占鎖沒有疑故,而我們此時(shí)是獲取獨(dú)占鎖的
所以直接返回杠览,也就是說代碼中直接拒絕 了我們 不允許 讀鎖降級為寫鎖
當(dāng)w弯菊!=0 且不是獨(dú)占鎖的線程也不可獲取鎖
if (c != 0) {
// (Note: if c != 0 and w == 0 then shared count != 0)
if (w == 0 || current != getExclusiveOwnerThread())
return false;
如果獲取鎖超過了最大值 拋出異常
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
設(shè)置state狀態(tài)
setState(c + acquires);
return true;
}
對于公平鎖來說 當(dāng)鎖還未被獲取纵势,且有隊(duì)列存在 那么write應(yīng)該block
對于非公平來說直接返回false
if (writerShouldBlock() ||
嘗試獲取鎖
!compareAndSetState(c, c + acquires))
return false;
獲取成功設(shè)置獨(dú)占標(biāo)識
setExclusiveOwnerThread(current);
return true;
}
ReentrantReadWriteLock.ReadLock的lock
共享鎖---當(dāng)我們的寫鎖被其他線程持有 那么我們是不可以獲取讀鎖踱阿,寫鎖排斥任何的鎖
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
當(dāng)前獲取的鎖
int c = getState();
如果寫鎖存在而且非本線程持有 直接返回
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
int r = sharedCount(c);
公平方面主要就是看看是否存在等待隊(duì)列
非公平方式的實(shí)現(xiàn)主要就是判斷head的下一個(gè)是否是寫鎖,也就是說如果是血鎖钦铁,就不去搶软舌,否則就去搶鎖
if (!readerShouldBlock() &&
r < MAX_COUNT &&
SHARED_UNIT可以留意
compareAndSetState(c, c + SHARED_UNIT)) {
if (r == 0) {
如果是第一次獲取 設(shè)置 firstReader 和firstReaderHoldCount
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
如果是第一個(gè)線程重復(fù)獲取 更新 firstReaderHoldCount
firstReaderHoldCount++;
} else {
代表是其他線程獲取
cachedHoldCounter 代表最后一個(gè)線程的對象,依賴threadlocal存儲著重入的次數(shù)
HoldCounter rh = cachedHoldCounter;
如果是第一次被其他線程獲取或者多次被其他線程獲取 (通過對比id)
if (rh == null || rh.tid != getThreadId(current))
生成一個(gè)新的cachedHoldCounter
cachedHoldCounter = rh = readHolds.get();
是當(dāng)前線程且rh不等于null
else if (rh.count == 0)
readHolds.set(rh);
給count增加1
rh.count++;
}
return 1;
}
輪詢的方式重復(fù)了上面的步驟
return fullTryAcquireShared(current);
}
執(zhí)行到這一步要么前面是head的next存在寫鎖(非公平)
要么是就是公平鎖下面有隊(duì)列
final int fullTryAcquireShared(Thread current) {
HoldCounter rh = null;
for (;;) {
int c = getState();
先檢測寫鎖是否被其他線程獲取牛曹,如果是直接返回
if (exclusiveCount(c) != 0) {
if (getExclusiveOwnerThread() != current)
return -1;
} else if (readerShouldBlock()) {
如果write應(yīng)該block 如果firstReader == current
可以嘗試去獲取讀鎖
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
} else {
如果rh==null佛点,檢測最后一個(gè)獲取讀鎖的線程是否有問題
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) {
rh = readHolds.get();
if (rh.count == 0)
readHolds.remove();
}
}
這邊如果獲取鎖不可能count=-1 直接返回
if (rh.count == 0)
return -1;
}
}
超出獲取的最大值 拋出異常
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
重復(fù)了我們上面的步驟
if (compareAndSetState(c, c + SHARED_UNIT)) {
if (sharedCount(c) == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
if (rh == null)
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
cachedHoldCounter = rh; // cache for release
}
return 1;
}
}
}
private void doAcquireShared(int arg) {
加入節(jié)點(diǎn)
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
如果前置節(jié)點(diǎn)是head 就獲取鎖,
if (p == head) {
int r = tryAcquireShared(arg);
獲取成功就設(shè)置head
if (r >= 0) {
設(shè)置head并釋放寫鎖
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
readerShouldBlock
公平方面主要就是看看是否存在等待隊(duì)列
非公平方式的實(shí)現(xiàn)主要就是判斷head的下一個(gè)是否是寫鎖黎比,也就是說如果是血鎖超营,就不去搶,否則就去搶鎖
final boolean apparentlyFirstQueuedIsExclusive() {
Node h, s;
return (h = head) != null &&
(s = h.next) != null &&
!s.isShared() &&
s.thread != null;
}
共享鎖的是否就是阅虫,先去消除線程中持有鎖的計(jì)數(shù)演闭,然后在修改state
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;
}
}