老师,AQS的doAcquireSharedInterruptibly方法中有一段代码作用不明白,请指教

来源:11-5 AQS简要分析

ice_wolf

2020-01-29

final Node p = node.predecessor();
if (p == head) {
     int r = tryAcquireShared(arg);
     if (r >= 0) {
         setHeadAndPropagate(node, r);
         p.next = null; // help GC
         failed = false;
         return;
      }
 }

老师,AQS的doAcquireSharedInterruptibly方法中无限循环中有这么一段代码我看不太懂它的作用,能不能请您大概讲一下,谢谢!

写回答

1回答

悟空

2020-01-30

/**
* Acquire in shared interruptible mode
* @param arg the acquire argument
*/private void doAcquireSharedInterruptibly(int arg) throws InterruptedException{
   final Node node = addWaiter(Node.SHARED);            // 1. 将当前的线程封装成 Node 加入到 Sync Queue 里面
   boolean failed = true;

   try {
       for(;;){
           final Node p = node.predecessor();          // 2. 获取当前节点的前继节点 (当一个n在 Sync Queue 里面, 并且没有获取 lock 的 node 的前继节点不可能是 null)
           if(p == head){
               int r = tryAcquireShared(arg);          // 3. 判断前继节点是否是head节点(前继节点是head, 存在两种情况 (1) 前继节点现在占用 lock (2)前继节点是个空节点, 已经释放 lock, node 现在有机会获取 lock); 则再次调用 tryAcquireShared 尝试获取一下
               if(r >= 0){
                   setHeadAndPropagate(node, r);       // 4. 获取 lock 成功, 设置新的 head, 并唤醒后继获取  readLock 的节点
                   p.next = null; // help GC
                   failed = false;
                   return;
               }
           }

           if(shouldParkAfterFailedAcquire(p, node) && // 5. 调用 shouldParkAfterFailedAcquire 判断是否需要中断(这里可能会一开始 返回 false, 但在此进去后直接返回 true(主要和前继节点的状态是否是 signal))
                   parkAndCheckInterrupt()){           // 6. 现在lock还是被其他线程占用 那就睡一会, 返回值判断是否这次线程的唤醒是被中断唤醒
               throw new InterruptedException();     // 7. 若此次唤醒是 通过线程中断, 则直接抛出异常
           }
       }
   }finally {
       if(failed){              // 8. 在整个获取中出错(比如线程中断/超时)
           cancelAcquire(node); // 9. 清除 node 节点(清除的过程是先给 node 打上 CANCELLED标志, 然后再删除)
       }
   }}


关于AQS的源码分析,麻烦同学看一下11-10小节,都有分析的哈。

2
0

深度解密Java并发工具,精通JUC,成为并发多面手

JUC全方位讲解,构建并发工具类知识体系

1599 学习 · 573 问题

查看课程