AQS底层为什么要采用双向链表

前置知识-链表的优势:

  • 灵活性:链表是动态的,而非数组一样的大小固定,对于插入和删除效率比较友好;
  • 内存利用率高:由于链表不像数组一样需要开辟一块连续的空间,利用的是碎片空间,因此对比数组,链表对空间的使用率更高;
  • 基础的数据结构:队列、栈、redis等,是实现各种数据结构的基础,尤其更是学习redis底层数据结构必备的知识储备;

正文:

AQS的底层就是采用双向链表,主要包括管理线程队列、快速的插入和删除、动态管理线程的状态、避免线程的阻塞和唤醒的开销。

优势:

  1. FIFO(先进先出):可在队列的前端和后端进行插入和删除、确保这按照锁的请求顺序进行处理。
  2. 高效:双向链表保证了可以双向遍历,而不是只从一个方向查找,保证了高并发情况下的高效运行。
  3. 管理线程状态:AQS使用了一个内部类Node来表示等待队列中的节点,‌这些节点通过双向链表连接。‌这些节点可以很容易地跟踪线程的状态,‌例如,‌是否已被取消、‌是否被中断等。‌
  4. 避免线程阻塞和唤醒的开销:‌刚加入到链表的线程首先会通过自旋的方式尝试去竞争锁,‌只有头节点的下一个节点才有必要去竞争锁,‌后续的节点竞争锁的意义不大,‌这样可以避免不必要的线程阻塞和唤醒的开销。‌

问题:为什么不采用单向链表?

解答:首先,单向链表的尾部节点只会记录下一个节点的位置,而不会记录上一个节点的,因此单向链表只会从一个方向查找,双向链表的节点会同时前驱和后继节点,因此无论从哪一个方向查找都可以,对于某些需要双向检索的同步操作和线程调度非常有用。

其次:后继节点,需要判断前驱节点的锁的状态,来判断本身节点是否需要继续阻塞等待,单向链表满足不了,因为找不到上一个节点,当然也无法判断。再有双向链表在线程等待的过程中支持高效的删除,以此移除取消和中断的线程节点。

最后:双向链表支持线程在队列中移动,AQS中的等待队列是一个动态的数据结构,需要支持在任意位置插入和删除节点。双向链表可以很方便地支持在任意位置插入和删除节点,而单向链表则需要从头节点开始遍历找到要插入或删除的节点位置,时间复杂度较高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值