面试题答案
一键面试- 队列数据结构:
- AQS使用的队列是一个双向链表结构,节点类型为
Node
。Node
类中包含前驱节点prev
、后继节点next
、线程thread
以及等待状态waitStatus
等属性。这种双向链表结构使得在队列中进行节点的添加、删除操作都比较高效,并且方便从队列头部或尾部进行遍历。
- AQS使用的队列是一个双向链表结构,节点类型为
- 线程排队操作:
- 当一个线程尝试获取锁失败时,会创建一个新的
Node
节点,将当前线程封装在节点中。 - 该节点会被插入到双向链表的尾部。具体过程如下:通过
compareAndSetTail
方法使用CAS(Compare - And - Swap)操作尝试将新节点设置为尾部节点,如果失败则说明有其他线程同时在进行相同操作,那么就通过循环不断尝试,直到成功。同时,新节点的前驱节点会设置为旧的尾部节点。
- 当一个线程尝试获取锁失败时,会创建一个新的
- 线程唤醒操作:
- 当持有锁的线程释放锁时,会唤醒队列头部的线程。
- 首先获取队列头部节点(即等待时间最长的节点),判断该节点的线程是否需要唤醒(通过检查节点的
waitStatus
等状态)。 - 如果需要唤醒,则通过
LockSupport.unpark
方法唤醒节点中的线程。被唤醒的线程会尝试重新获取锁,获取成功后会将自己设置为新的头部节点,原头部节点的后继节点成为新的头部节点,原头部节点的前驱和后继节点都设置为null
,以便垃圾回收。如果获取锁失败,该线程会重新进入等待状态。
通过这样的队列结构和操作机制,AQS实现了多个线程竞争锁等同步场景下的同步控制,确保线程按照一定的顺序获取锁,避免了竞争条件和死锁等问题。