AQS源码解读(五)——从acquireShared探索共享锁实现原理,何为共享?如何共享?

  • p不是头结点 or 获取锁失败,判断是否应该被阻塞

  • 前继节点的ws = SIGNAL 时应该被阻塞

*/

if (shouldParkAfterFailedAcquire(p, node) &&

parkAndCheckInterrupt())

interrupted = true;

}

} finally {

if (failed)

cancelAcquire(node);

}

}

(1)setHeadAndPropagate传播唤醒后继

自旋判断新节点node前驱是head,且尝试获取共享锁成功,则需要传播唤醒共享后继节点。基本流程如下:

  1. node出队列,并成为新的head。

  2. 判断是否满足传播条件。

  3. 如若node还有后继且后继是共享节点,则执行唤醒操作doReleaseShared

(共享锁的传播模式比较复杂,如需深入了解,请阅读拙作《AQS源码解读(七)——从PROPAGATE和setHeadAndPropagate()分析共享锁的传播性》

private void setHeadAndPropagate(Node node, int propagate) {

Node h = head; // Record old head for check below

//设置node为新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();

}

}

(2)判断是否应该阻塞和阻塞线程

共享锁判断判断是否应该阻塞和阻塞线程的代码和独占锁的完全一样,不过多赘述。shouldParkAfterFailedAcquire主要做了如下几步:

  1. 判断node前驱状态是否为SIGNAL,是则直接返回true。

  2. node前驱状态不是SIGNAL,有可能是ws>0,说明前驱取消了,自旋跳过取消的节点,并寻找链接一个正常的前驱。

  3. node前驱状态不是SIGNAL,有可能是0(初始化状态)或PROPAGATE(传播状态),修改node前驱状态为SIGNAL

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {

int ws = pred.waitStatus;

if (ws == Node.SIGNAL)

/*

  • This node has already set status asking a release

  • to signal it, so it can safely park.

  • node拿锁失败,前继节点的状态是SIGNAL,node节点可以放心的阻塞,

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值