面试的时候被问到AQS会不会一脸懵逼呢?今天来学习一下AQS吧!
看看这个听起来高大上又难以回答的东西到底是个啥?
1.什么是AQS
JUC包中 的很多同步器如ReentrantLock、Semaphore、CountDownLatch等等都是有一些基础的共同的行为,比如:等待队列、条件队列、独占获取、共享获取等等,这些抽象行为就被封装成一个抽象类,就是AbstractQueuedSynchronizer(抽象队列同步器)。
一般是通过一个内部类Sync继承 AQS
将同步器所有调用都映射到Sync对应的方法
看图,抽象类AbstractQueuedSynchronizer的实现类几乎都是各种我们常见的JUC工具类中的内部类——各种Sync。
AQS具有以下特性:独占/共享,公平/非公平,可重入,阻塞等待队列,允许中断
2.AQS核心结构
1.AQS内部维护属性 volatile int state
state表示资源的可用状态
state的三种访问方式:
getState() setState() compareAndSetState()
2.定义了两种资源访问方式:
Exclusive-独占,只有一个线程能执行,如ReentrantLock
Share-共享,多个线程可以同时执行,如Semaphore/CountDownLatch
3.AQS实现时主要实现以下几种方法:
isHeldExclusively():该线程是否正在独占资源。只有用到condition才需要去实现它。
tryAcquire(int):独占方式。尝试获取资源,成功则返回true,失败则返回false。
tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回false。
tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表 示成功,且有剩余资源。
tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回 false。
3.AQS定义两种队列:
同步等待队列: 主要用于维护获取锁失败时入队的线程。
条件等待队列: 调用await()的时候会释放锁,然后线程会加入到条件队列,调用signal()唤醒的时候会把条件队 列中的线程节点移动到同步等待队列中,等待再次获得锁。
/**
* Status field, taking on only the values:
* SIGNAL: The successor of this node is (or will soon be)
* blocked (via park), so the current node must
* unpark its successor when it releases or
* cancels. To avoid races, acquire methods must
* first indicate they need a signal,
* then retry the atom