AQS源码学习

Posted 技术无产者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AQS源码学习相关的知识,希望对你有一定的参考价值。

Java并发之AQS详解 - waterystone - 博客园java、多线程、并发、AbstractQueuedSynchronized、AQS、Lock、Mutex、ReentrantLock、Semaphore、CountDownLatch、线程同步https://www.cnblogs.com/waterystone/p/4920797.html学这篇文章中存在几个疑惑的地方做以记录:

1.head节点的线程是当前持有资源可运行的线程,第 二个节点在parkAndCheckInterrupt方法里被park阻 塞,当前一个节点也就是head节点唤醒它后,它才会 成为head节点

2. 其ReentrantLock实现是AQS,它的阻塞底层是使用LockSupport.park方法进行等待的,LockSupport.park是响应中断的,当线程进入ReentrantLock.lock方法里面进行阻塞后,此时调用Thread.interrupt()方法之后,该线程是会被中断被唤醒的,但是唤醒之后,会调用LockSupport.park再次进入等待状态(由于自旋),所以仅从宏观(表面)上面看ReentrantLock.lock是不支持响应中断的,从微观(原理)上面讲ReentrantLock.lock内部确实中断了响应,但是还是会被迫进行等待状态(看acquireQueued这块源码,被唤醒后不符合条件继续进入等等状态,然后通过selfinterrupt方法自我中断,所以Reentrantlock.lock是不响应中断的)。

3.

这个方法中,如果等待的线程没有拿到资源,会一直通过parkAndCheckInterrupt()方法阻塞,只有当前节点是head节点的后继结点时,它才会真正的处于运行状态,否则就算中途被意外中断导致下线程唤醒,通过自旋会继续陷入等待状态。

final boolean acquireQueued(final Node node, int arg) 
 2     boolean failed = true;//标记是否成功拿到资源
 3     try 
 4         boolean interrupted = false;//标记等待过程中是否被中断过
 5         
 6         //又是一个“自旋”!
 7         for (;;) 
 8             final Node p = node.predecessor();//拿到前驱
 9             //如果前驱是head,即该结点已成老二,那么便有资格去尝试获取资源(可能是老大释放完资源唤醒自己的,当然也可能被interrupt了)。
10             if (p == head && tryAcquire(arg)) 
11                 setHead(node);//拿到资源后,将head指向该结点。所以head所指的标杆结点,就是当前获取到资源的那个结点或null。
12                 p.next = null; // setHead中node.prev已置为null,此处再将head.next置为null,就是为了方便GC回收以前的head结点。也就意味着之前拿完资源的结点出队了!
13                 failed = false; // 成功获取资源
14                 return interrupted;//返回等待过程中是否被中断过
15             
16             
17             //如果自己可以休息了,就通过park()进入waiting状态,直到被unpark()。如果不可中断的情况下被中断了,那么会从park()中醒过来,发现拿不到资源,从而继续进入park()等待。
18             if (shouldParkAfterFailedAcquire(p, node) &&
19                 parkAndCheckInterrupt())
20                 interrupted = true;//如果等待过程中被中断过,哪怕只有那么一次,就将interrupted标记为true
21         
22      finally 
23         if (failed) // 如果等待过程中没有成功获取资源(如timeout,或者可中断的情况下被中断了),那么取消结点在队列中的等待。
24             cancelAcquire(node);
25     
26 

 

以上是关于AQS源码学习的主要内容,如果未能解决你的问题,请参考以下文章

AQS源码学习

AQS源码解析

JDK8,AQS源码解读

Semaphore 源码解读

并发编程Java并发编程-看懂AQS的前世今生

AQS学习