一.共享式获取同步状态
1.acquireShared
/**
* 共享式获取锁
* tryAcquireShared()尝试获取同步状态 当返回值>0时,代表到获取同步状态
*/
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0) {
doAcquireShared(arg);
}
}
2.doAcquireShared
/**
* 共享式获取状态 不可中断
* @param arg the acquire argument
*/
private void doAcquireShared(int arg) {
//添加节点到等待队列中
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
//自旋的获取同步状态
for (; ; ) {
//前驱节点
final Node p = node.predecessor();
//前驱节点 == 头结点
if (p == head) {
//尝试获取同步状态
int r = tryAcquireShared(arg);
//返回值>0 代表获取同步状态成功,从自旋中退出
if (r >= 0) {
//将当前节点设置为头结点 唤醒后继节点
setHeadAndPropagate(node, r);
//帮助GC
p.next = null;
if (interrupted) {
//获取成功 进行自行中断
selfInterrupt();
}
failed = false;
return;
}
}
//shouldParkAfterFailedAcquire 判断线程是否需要被阻塞
//parkAndCheckInterrupt 阻塞线程
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) {
interrupted = true;
}
}
} finally {
//获取失败 取消节点
if (failed) {
cancelAcquire(node);
}
}
}
3.setHeadAndPropagate
/**
* 将当前节点设置为头结点 并调用doReleaseShared()方法
*/
private void setHeadAndPropagate(Node node, int propagate) {
//更新头结点
Node h = head;
setHead(node);
if (propagate > 0 || h == null || h.waitStatus < 0 || (h = head) == null || h.waitStatus < 0) {
Node s = node.next;
//共享模式 唤醒后继线程
if (s == null || s.isShared()) {
doReleaseShared();
}
}
}
二.共享式释放同步状态
1.releaseShared()
/**
* 共享式释放锁
*/
public final boolean releaseShared(int arg) {
//tryReleaseShared()尝试释放锁
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
2.doReleaseShared()
/**
* 共享模式下 释放同步状态
*/
private void doReleaseShared() {
for (; ; ) {
//获取头结点
Node h = head;
//头结点不为空并且不等于尾结点
if (h != null && h != tail) {
int ws = h.waitStatus;
//若头结点对应的状态是SIGNAL 代表后继节点对应的线程需要被unpark()唤醒
if (ws == Node.SIGNAL) {
//将头结点对应的线程状态 = 空状态
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) {
continue;
}
//唤醒后继节点的线程
unparkSuccessor(h);
}
//头结点对应的状态为空状态 , 则设置尾结点对应的线程所拥有的共享锁为其他线程获取锁的空状态
else if (ws == 0 && !compareAndSetWaitStatus(h, 0, Node.PROPAGATE)) {
continue;
}
}
//若头节点发生变化,则继续循环
if (h == head) {
break;
}
}
}