06.JUC 锁 - AQS - 共享模式
2017-02-13 00:00
465 查看
##基本概念
AQS 的共享模式,表示 AQS 通过共享模式获取/释放锁。该类对应的方法为 acquireShared/acquireSharedInterruptibly/tryAcquireSharedNanos、 releaseShared。
##acquireShared
acquireShared 表示以共享模式获取锁对象,并忽略中断。
tryAcquireShared: 与独占模式一样留给子类实现。
doAcquireShared:负责获取锁失败后的操作。
###1.doAcquireShared
下面来看 doAcquireShared 的实现过程:
###2.setHeadAndPropagate
该方法负责设置新的头节点,并执行传播操作。
传播操作具体是节点指唤等待队列的第一个节点后,被唤醒的节点由于自旋的缘故又会调用该方法唤醒其后续点,直到整个队列都被唤醒。
下面来看它的实现过程:
###3.doReleaseShared
再来看看 doReleaseShared 的实现过程:
整个过程如下图所示:
##acquireSharedInterruptibly
acquireSharedInterruptibly表示以共享模式获取锁对象,不忽略中断。
关键来看 doAcquireSharedInterruptibly,它与 doAcquireShared 的区别在于,如果发现线程的中断标志位被置为 true,则会抛出异常中断线程。区别如下:
##tryAcquireSharedNanos
tryAcquireSharedNanos表示以共享模式获取锁对象,尝试获取失败,则线程进入阻塞状态一段时间。线程在进入阻塞状态后有两种情况:
进入阻塞状态,一直到 nanosTimeout 超时,返回 false;
进入阻塞状态,时长未到 nanosTimeout 被唤醒,则通过自旋再次尝试,成功获取锁或直到超时返回结果。
下面来看它的实现过程:
##releaseShared
该操作表示通过共享模式释放锁对象。
AQS 的共享模式,表示 AQS 通过共享模式获取/释放锁。该类对应的方法为 acquireShared/acquireSharedInterruptibly/tryAcquireSharedNanos、 releaseShared。
##acquireShared
acquireShared 表示以共享模式获取锁对象,并忽略中断。
public final void acquireShared(int arg) { if (tryAcquireShared(arg) < 0) { doAcquireShared(arg); } }
tryAcquireShared: 与独占模式一样留给子类实现。
doAcquireShared:负责获取锁失败后的操作。
###1.doAcquireShared
下面来看 doAcquireShared 的实现过程:
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); // 成功则更新等待队列的头节点 if (r >= 0) { // 关键 setHeadAndPropagate(node, r); p.next = null; if (interrupted){ selfInterrupt(); } failed = false; return; } } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()){ interrupted = true; } } } finally { if (failed){ cancelAcquire(node); } } }
###2.setHeadAndPropagate
该方法负责设置新的头节点,并执行传播操作。
传播操作具体是节点指唤等待队列的第一个节点后,被唤醒的节点由于自旋的缘故又会调用该方法唤醒其后续点,直到整个队列都被唤醒。
下面来看它的实现过程:
private void setHeadAndPropagate(Node node, int propagate) { // 设置新的头节点,即出队操作 Node h = head; setHead(node); // 唤醒该节点的下个节点 if (propagate > 0 || h == null || h.waitStatus < 0) { Node s = node.next; if (s == null || s.isShared()){ // 释放共享锁操作,实质就是唤醒等待队列的节点 doReleaseShared(); } } }
###3.doReleaseShared
再来看看 doReleaseShared 的实现过程:
private void doReleaseShared() { // 循环,直至唤醒同步等待队列中的所有节点 for (;;) { Node h = head; // 判断同步等待队列是否为空 if (h != null && h != tail) { int ws = h.waitStatus; if (ws == Node.SIGNAL) { if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)){ continue; // loop to recheck cases } // 唤醒 h 的后继节点(同时将 h 等待状态置为 CANCELED) unparkSuccessor(h); } else if (ws == 0 && !compareAndSetWaitStatus(h, 0, Node.PROPAGATE)){ continue; // loop on failed CAS } } if (h == head){ break;// loop if head changed } } }
整个过程如下图所示:
##acquireSharedInterruptibly
acquireSharedInterruptibly表示以共享模式获取锁对象,不忽略中断。
public final void acquireSharedInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()){ // 抛出异常... } if (tryAcquireShared(arg) < 0){ doAcquireSharedInterruptibly(arg); } }
关键来看 doAcquireSharedInterruptibly,它与 doAcquireShared 的区别在于,如果发现线程的中断标志位被置为 true,则会抛出异常中断线程。区别如下:
if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt()){ throw new InterruptedException(); }
##tryAcquireSharedNanos
tryAcquireSharedNanos表示以共享模式获取锁对象,尝试获取失败,则线程进入阻塞状态一段时间。线程在进入阻塞状态后有两种情况:
进入阻塞状态,一直到 nanosTimeout 超时,返回 false;
进入阻塞状态,时长未到 nanosTimeout 被唤醒,则通过自旋再次尝试,成功获取锁或直到超时返回结果。
下面来看它的实现过程:
public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException { if (Thread.interrupted()){ // 抛出异常... } return tryAcquireShared(arg) >= 0 || // 实现原理与独占模式的 doAcquireNanos 类似,这里不再分析 doAcquireSharedNanos(arg, nanosTimeout); }
##releaseShared
该操作表示通过共享模式释放锁对象。
public final boolean releaseShared(int arg) { if (tryReleaseShared(arg)) { // 关键 doReleaseShared(); return true; } return false; }
相关文章推荐
- 06.JUC 锁 - AQS - 共享模式
- JUC源码分析7-locks-AQS-共享模式
- 3.从AbstractQueuedSynchronizer(AQS)说起(2)——共享模式的锁获取与释放
- 深入浅出AQS之共享锁模式
- JUC源码分析6-locks-AQS-独占模式
- 共享模式下CISCO防火墙拦截数据包引起的ORA-12541
- oracle专用模式修改为共享模式
- 【CDP-云设计模式】第4章,5.状态共享模式(State Sharing Pattern)
- Java多线程系列--“JUC集合”06之 ConcurrentSkipListSet
- javascript优化--06模式(对象)01
- 06 Activity 4中启动模式
- oracle共享模式与专用模式
- 06、人人都会设计模式:观察者模式--Observer
- Java多线程系列--【JUC线程池 06】- Callable和Future
- Java设计模式_结构型_享元模式_实现单元的共享
- 04.JUC 锁- AQS - CLH 队列
- 07.JUC 锁 - AQS - Condition
- 打开ASP.NET Web项目时,此项目的默认Web访问模式设置为文件共享, 但是无法从路径“...”打开“...”处的项目文件夹。返回的错误是: 无法打开Web项目“”。返回的错误是: 无法打开Web项目“...”。文件路径“...”怀URL“...”不
- 工作组模式下Windows共享不需要密码也能访问
- Oracle Dedicated server 和 Shared server(专用模式 和 共享模式 MTS) 说明