AQS原理

概念

AQS是AbstarctQueuedSynchronizer 的简称 ,是一个用于构建锁和同步容器的框架。

juc并发 包内许多类都是基于 AQS 构建的

  • ReentrantLock
  • ReentrantReadWriteLock
  • FutureTask

AQS 解决了在实现同步容器时大量的细节问题。
在这里插入图片描述

  • AQS 使用一个 FIFO 队列表示排队等待锁的线程,队列头结点称作 “哨兵节点” ,它不与任何线程关联。
  • 其他的节点与等待线程关联,每个阶段维护一个等待状态 waitStatus。

功能

  • 独占锁:每次只能有一个线程持有锁, ReentrantLock 就是以独占方式实现的互斥锁;
  • 共享锁:允许多个线程同时获取锁,并发访问共享资源,比如 ReentrantReadWriteLock。

内部原理

AQS 的实现依赖内部的同步队列,也就是 FIFO 的双向队列,如果当前线程竞争锁失败,那么 AQS 会把当前线程以及等待状态信息构造成一个 Node 加入到同步队列中,同时再阻塞该线程。当获取锁的线程释放锁以后,会从队列中唤醒一个阻塞的节点 (线程)。
在这里插入图片描述
一个节点表示一个线程,它保存着线程的引用(thread)、状态(waitStatus)、前驱节点(prev)、后继节点(next),其实就是个双端双向链表

  • AQS 队列内部维护的是一个 FIFO 的双向链表,这种结构的特点是每个数据结构都有两个指针,分别指向直接的后继节点和直接前驱节点。
  • 双向链表可以从任意一个节点开始,很方便的访问前驱和后继。
  • 每个 Node 其实是由线程封装,当线程争抢锁失败后会封装成 Node 加入到 ASQ 队列中去。

工作流程

添加线程

当出现锁竞争以及释放锁的时候,AQS 同步队列中的节点会发生变化
在这里插入图片描述

  • 队列操作的变化:新的线程封装成 Node 节点追加到同步队列中,设置 prev 节点以及修改当前节点的前置节点的 next 节点指向自己;
  • tail 指向变化:通过同步器将 tail 重新指向新的尾部节点。
销毁线程

第一个 head 节点表示获取锁成功的节点,当头结点在释放同步状态时,会唤醒后继节点,如果后继节点获得锁成功,会把自己设置为头结点
在这里插入图片描述

  • head 节点指向:修改 head 节点指向下一个获得锁的节点;
  • 新的获得锁的节点:第二个节点被 head 指向了,此时将 prev 的指针指向 null,因为它自己本身就是第一个首节点,所以 pre 指向 null。

AQS 与 ReentrantLock 的联系

ReentrantLock 是根据 AQS 实现的独占锁,提供了两个构造方法

 public ReentrantLock() {
        sync = new NonfairSync();
    }
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

ReentrantLock 有三个内部类:Sync,NonfairSync,FairSync
在这里插入图片描述

这三个内部类都是基于 AQS 进行的实现,所以ReentrantLock 是基于 AQS 进行的实现。

ReentrantLock 提供两种类型的锁:

  • 公平锁-FairSync
  • 非公平锁-NonfairSync
  • 默认实现是 NonFairSync。
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值