一、AQS 是如何控制同步状态的?说说 AQS 的工作原理?
AQS 是通过一个int类型的变量state来控制同步状态的。AQS 既可以实现共享锁,也可以实现互斥锁,state根据锁的类型的不同表示的含义不同。
以互斥锁为例,多个线程 通过竞争 state变量的值来判断锁的状态,并通过 CAS 操作来保证同步状态 state 变更的原子性。
获取同步状态失败的线程会存储到一个双向链表中进行等待,并通过park()方法来阻塞自己,从而释放 CPU 的资源。
AQS 通过这 2 种机制来完成一个抽象的队列同步器,实现多线程之间同步访问。
二、AQS 为什么用双向链表呢?
- 双向链表允许常数时间复杂度完成节点的插入与删除操作,新的节点需要加入队列进行等待时,只需要修改pre和next指针,就可以把线程添加到队列尾部。同样线程移除操作也非常高效,针对频繁入队出队的同步控制也很重要。
- AQS 在设计上遵循先进先出获取锁原则,双向链表支持按顺序遍历。
- 在某些情况下,线程被取消或锁的持有者直接唤醒某个特定的等待线程时,双向链表能够提供从前往后或从后往前遍历,便于快速定位到特定节点进行操作。
- 双向链表使AQS 不仅可以从头开始唤醒等待线程,也可以从特定位置唤醒等待线程,这种灵活性单链表和数组难以实现。
三、说一下 AQS 中的 Condition 是如何实现线程的等待和通知机制的?它和wait/notify的区别?
Condition 内部提供了一个条件队列,专门用来管理调用了await方法被阻塞的线程,这线程在加入到这个条件队列之后,同时会释放锁,并挂起等待,然后被挂起等待的线程可以通过signal方法唤醒。
被唤醒的线程需要重新加入到 AQS 队列中去重新竞争锁,因为 Condition 是基于条件的等待机制,所以它必须结合锁来使用。
和wait/notify的区别:
1、condition 能针对特定条件精准唤醒线程。
2、condition可以为不同条件橱窗就不同的等待队列方便管理。
3、condition是基于 API 设计,提供了更灵活的控制手段。