一、AQS概念

AbstractQueuedSynchronized简称AQS,AQS定义了一套多线程访问共享资源的同步器框架,是一个依赖状态state的同步器。具备如下特性:
阻塞等待队列
共享锁/独占锁
公平锁/非公平锁
可重入 - 通过对state进行 +1来实现重入
允许中断
子类可以通过重写以下方法来控制AQS内部的一个state同步变量实现各种功能。
独占式 - 资源互斥,一次只能一个线程获取锁(ReentrantLock)
共享模式 - 资源共享
AQS提供了四个空实现,前两个为独占式,后两个为共享式

  1. //独占式获取锁
  2. protected boolean tryAcquire(int arg)
  3. //独占式释放锁
  4. protected boolean tryRelease(int arg
  5. //共享式获取锁,返回值表示获取锁后还剩余的许可数量
  6. protected int tryAcquireShared(int arg)
  7. //共享式释放锁
  8. protected boolean tryReleaseShared(int arg)

二、设计要点

  • 状态:一个被volatile修饰的int变量,已保证可见性,共享资源
  • 队列:队列通常是一个等待的集合,大多数以链表的形式实现。队列采用的是悲观锁的思想,表示当前所等待的资源,状态或者条件短时间内可能无法满足。因此,它会将当前线程包装成某种类型的数据结构,扔到一个等待队列中,当一定条件满足后,再从等待队列中取出。
  • CAS:CAS操作是最轻量的并发处理,采用的是乐观锁的思想,因此常常伴随着自旋,如果发现当前无法成功地执行CAS,则不断重试,直到成功为止,自旋的的表现形式通常是一个死循环for(;;)。CAS操作保证了同一个时刻,只有一个线程能修改成功,从而保证了线程安全,CAS操作基本是由Unsafe工具类的compareAndSwapXXX来实现的;

    三、核心实现

    状态

    state表示共享资源,当state=0,表示无锁,state != 0,表示有线程持有锁,当state > 1时,表示锁重入

    1. private volatile int state;
    2. protected final int getState()
    3. protected final void setState(int newState)
    4. //通过cas进行设置值
    5. protected final boolean compareAndSetState(int expect, int update)

    如何查看哪个线程持有锁

    1. //持有锁的线程
    2. private transient Thread exclusiveOwnerThread;

    队列

    AQS中,队列的实现是一个双向链表,被称为sync queue,它表示所有等待锁的线程的集合;在AQS中用Node节点来包装线程

    1. static final class Node {
    2. /** Marker to indicate a node is waiting in shared mode */
    3. static final Node SHARED = new Node();
    4. /** Marker to indicate a node is waiting in exclusive mode */
    5. static final Node EXCLUSIVE = null;
    6. /** waitStatus value to indicate thread has cancelled */
    7. static final int CANCELLED = 1;
    8. /** waitStatus value to indicate successor's thread needs unparking */
    9. static final int SIGNAL = -1;
    10. /** waitStatus value to indicate thread is waiting on condition */
    11. static final int CONDITION = -2;
    12. /**
    13. * waitStatus value to indicate the next acquireShared should
    14. * unconditionally propagate
    15. */
    16. static final int PROPAGATE = -3;
    17. volatile int waitStatus;
    18. volatile Node prev;
    19. volatile Node next;
    20. volatile Thread thread;
    21. Node nextWaiter;
    22. final boolean isShared() {
    23. return nextWaiter == SHARED;
    24. }
    25. final Node predecessor() throws NullPointerException {
    26. Node p = prev;
    27. if (p == null)
    28. throw new NullPointerException();
    29. else
    30. return p;
    31. }
    32. Node() {
    33. }
    34. Node(Thread thread, Node mode) { // Used by addWaiter
    35. this.nextWaiter = mode;
    36. this.thread = thread;
    37. }
    38. Node(Thread thread, int waitStatus) { // Used by Condition
    39. this.waitStatus = waitStatus;
    40. this.thread = thread;
    41. }
    42. }

    Node的属性很多,但是可以分为四类 ```java // 节点所代表的线程 volatile Thread thread;

// 双向链表,每个节点需要保存自己的前驱节点和后继节点的引用 volatile Node prev; volatile Node next;

// 线程所处的等待锁的状态,初始化时,该值为0,表示当前没有现成获得锁 volatile int waitStatus; //表示超时或者中断,节点被设置为取消状态,被设置为取消状态的节点不应该再去竞争锁,他应该是一直 //被取消状态,不能变为其他状态, static final int CANCELLED = 1; //后继节点的线程处于等待状态,当前节点的线程释放了同步状态或者取消,会通知后继节点去获取锁 //表示后继结点在等待当前结点唤醒。后继结点入队时,会将前继结点的状态更新为SIGNAL static final int SIGNAL = -1; static final int CONDITION = -2; static final int PROPAGATE = -3;

// 该属性用于条件队列或者共享锁 Node nextWaiter;

  1. waitStatus - 表示当前node所代表的线程等待锁的状态<br />在独占锁模式下,我们只需关注CANCELLED SIGNAL两种状态即可<br />nextWaiter属性,它在独占模式下永远为null,仅仅起到一个标记作用,没有任何意义
  2. <a name="mPDdk"></a>
  3. ### sys queue
  4. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1161651/1615527450890-ee115767-6c92-477f-b65b-de3e8b5c3638.png#crop=0&crop=0&crop=1&crop=1&height=255&id=nwGWj&margin=%5Bobject%20Object%5D&name=image.png&originHeight=292&originWidth=732&originalType=binary&ratio=1&rotation=0&showTitle=false&size=78474&status=done&style=none&title=&width=638)<br />AQS中的队列是一个CLH队列,**它的head节点永远是一个哑节点**(new Node()的实例对象),不持有任何线程,因此head所指向的node的thread属性永远为null,只有从次头节点往后的所有节点才代表了所有等待锁的线程。也就是说,在当前线程没有抢到锁被包装成Node扔到队列中时,**即使队列是空的,它也会排在第二个。**
  5. - `thread`:表示当前Node所代表的线程
  6. - `waitStatus`:表示节点所处的等待状态,共享锁模式下只需关注三种状态:`SIGNAL` `CANCELLED` `初始态(0)`
  7. - `prev` `next`:节点的前驱和后继
  8. - `nextWaiter`:进作为标记,值永远为null,表示当前处于独占锁模式
  9. <a name="tlqud"></a>
  10. ## CAS操作
  11. 都是通过Unsafe类的compareAndSwapXXX方法实现
  12. ```java
  13. protected final boolean compareAndSetState(int expect, int update) {
  14. return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
  15. }
  16. private final boolean compareAndSetHead(Node update) {
  17. return unsafe.compareAndSwapObject(this, headOffset, null, update);
  18. }
  19. private final boolean compareAndSetTail(Node expect, Node update) {
  20. return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
  21. }
  22. private static final boolean compareAndSetWaitStatus(Node node, int expect,int update) {
  23. return unsafe.compareAndSwapInt(node, waitStatusOffset, expect, update);
  24. }
  25. private static final boolean compareAndSetNext(Node node, Node expect, Node update) {
  26. return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
  27. }