AQS详解

Node节点

  • 获取同步状态失败的线程,等待的状态,以及先驱和后继节点 将其加入同步队列,同事会阻塞当前线程,同步状态释放时, 会把首节点中的线程唤醒,使其再次获取同步状态
    static final class Node {
        /** 标志着一个节点是处在共享模式*/
        static final Node SHARED = new Node();
        /** 独占模式 */
        static final Node EXCLUSIVE = null;
        /** waitStatus 的值 标志着被取消 */
        static final int CANCELLED =  1;
        /** waitStatus 唤醒*/
        static final int SIGNAL    = -1;
        /** waitStatus 表示线程正在等待条件 */
        static final int CONDITION = -2;
        /**
         *无条件的将共享状态传播给下一个节点
         */
        static final int PROPAGATE = -3;

        /**
         * Status field, taking on only the values:
         *   SIGNAL:    -1 后继节点是阻塞的在阻塞队列中,所以当前节点当释放或者取消的时候必须唤醒他的后继。

         *   CANCELLED:  1 这个在同步队列中等待的节点由于超时或者中断,必须从同步队列取消,节点从来不会离开这个状态,
                         尤其是,一个被取消的节点线程不会再阻塞
         *   CONDITION:  -2  节点在等待队列中
         *   PROPAGATE:  -3 下一次共享模式同步状态获取将会无条件传播下去
         *   0:          初始化
         *
         *负数表示一个节点不需要唤醒,所以大部分代码不需要检查,只是标志
         */
        volatile int waitStatus;

        /**
         当前节点检查waitStatus状态依赖他连接到先驱的节点。在进入同步队列时分配,
         在移除队列的时候归零(为了GC),在取消一个先驱节点时,当发现一个没有取消的节点时,
         会短路,这种情况总是存在的,因为头结点永远不会被取消:一个节点编程头结点只是作为成功获取的结果,
         并且一个线程只有取消自己,不管其他的节点。
         */
        volatile Node prev;

        /**
         连接到的后继的节点在当前节点或线程释放时释放,进入同步队列时分配,
         在绕过被取消的先驱节点时调整,并且在出对时取消(for GC)。
         enq不会分配先驱节点的next,
         所以看到一个节点的next是null不代表那是队列的结尾,
         如果一个节点的next是null,可以从tail向前双重确认。
         如果一个节点状态设置为取消next将会指向自己
         */
        volatile Node next;

        /**
         * The thread that enqueued this node.  Initialized on
         * construction and nulled out after use.
         */
        volatile Thread thread;
        Node nextWaiter;
        final boolean isShared() {
            return nextWaiter == SHARED;
        }
        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

共享资源state

/**
同步状态 代表争用的共享资源,不同的自定义同步器争用共享资源的方式也不一样,
自定义同步器在实现时只需要实现共享资源state的共享与释放的方式即可
*/
private volatile int state;
protected final int getState() {
   return state;
}
protected final void setState(int newState) {
   state = newState;
}

enq将node插入队列

/**
* Inserts node into queue, initializing if necessary. See picture above.
* @param node the node to insert
* @return node's predecessor
*/
private Node enq(final Node node) {
   for (;;) {//通过死循环CAS将节点正确加入queue中
       Node t = tail;
       if (t == null) { // Must initialize
           if (compareAndSetHead(new Node()))
               tail = head;
       } else {
           node.prev = t;
           if (compareAndSetTail(t, node)) {
               t.next = node;
               return t;
           }
       }
   }
}

/**
*将当前线程新建一个节点并入队
*/
private Node addWaiter(Node mode) {
   Node node = new Node(Thread.currentThread(), mode);
   // 快速入队,如果失败就进入enq循环入队
   Node pred = tail;
   if (pred != null) {
       node.prev = pred;
       if (compareAndSetTail(pred, node)) {
           pred.next = node;
           return node;
       }
   }
   enq(node);
   return node;
}

shouldParkAfterFailedAcquire:检查并更新一个节点获取锁失败
如果这个线程应该被阻塞就返回true,这个在循环获取锁的代码中是主要的信号控制

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
   int ws = pred.waitStatus;
   if (ws == Node.SIGNAL)
       //前驱节点是signal,那么可以安全park
       return true;
   if (ws > 0) {
       //前驱节点被cancel,那就跳过前驱节点,向前查找直到有前驱节点的ws小于0
       do {
           node.prev = pred = pred.prev;
       } while (pred.waitStatus > 0);
       pred.next = node;
   } else {
       /*ws必须是0或者是PROPAGATION,表明我们需要一个唤醒后继的信号,
       但是不能阻塞,调用者需要重新确认他是否在阻塞前不能获取锁
        */
       compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
   }
   //这里返回false让它再次确认ws是否cas设置为signal
   return false;
}
//中断当前线程
static void selfInterrupt() {
   Thread.currentThread().interrupt();
}

/**
* Convenience method to park and then check if interrupted
*
* @return {@code true} if interrupted
*/
private final boolean parkAndCheckInterrupt() {
   LockSupport.park(this);
   return Thread.interrupted();
}

使用addWaiter入队之后,就用acquireQueued再次获取锁,
只有获取成功才返回,这个过程中,该线程可能被挂起

final boolean acquireQueued(final Node node, int arg) {
   boolean failed = true;
   try {
       boolean interrupted = false;
       for (;;) {
           final Node p = node.predecessor();
           if (p == head && tryAcquire(arg)) {//node的前驱节点是head,并且获取到锁,就设置node为头节点
               setHead(node);
               p.next = null; // help GC
               failed = false;
               return interrupted;
           }
           //如node应该park并且已中断,那么node就被挂起,直到被唤醒,
           //就继续获取锁,直到获取到锁才会返回
           if (shouldParkAfterFailedAcquire(p, node) &&
               parkAndCheckInterrupt())
               interrupted = true;
       }
   } finally {
       if (failed)
           cancelAcquire(node);
   }
}

doAcquireInterruptibly:以中断独占方式获取锁

private void doAcquireInterruptibly(int arg)
   throws InterruptedException {
   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;
           }
           if (shouldParkAfterFailedAcquire(p, node) &&
               parkAndCheckInterrupt())
              <B>throw new InterruptedException();</B> 
       }
   } finally {
       if (failed)
           cancelAcquire(node);
   }
}

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);//负数说明获取锁失败,0说明获取成功,但是后面节点不能再是共享模式
              //大于0说明队列中的后继节点还可以继续使用共享模式
               if (r >= 0) {
                   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);
   }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值