Java并发之AQS

什么是AQS

AQS (abstructeQueuedSynchronizer)同步器,用来实现锁的一个框架,在synchronized基础功能上扩展了很多功能,比如 可中断,可以取消获取锁造成的阻塞等等。它是一个 Java 提高的底层同步工具类,用一个 int 类型的变量表示同步状态,并提供了一系列的 CAS 操作来管理这个同步状态。

AQS的工作模式

1.独占模式,同一时间只能有一个线程获取锁成功,当锁被获取成功后,其他线程获取锁就会失败进入等待队列

2.共享模式,同一时间可以有多个线程获取锁,用于控制一定量的并发执行。

AQS的三个关注点

  • 同步状态的原子性控制
  • 同步队列和等待队列的数据结构
  • 线程的等待与唤醒

关注一 :同步状态的原子性控制

同步状态state,通过volatile 配合 CAS操作就能实现并发下的原子性操作;

在独占模式下,同步状态state=1表示锁被其他获取了,state=0表示锁处于空闲;

在共享模式下,state 通常用来表示可用资源的数量或者某种共享状态的级别。例如,在一个计数信号量(Semaphore)中,state 可能表示剩余可用许可的数量;在读写锁的读取部分,state 可能表示当前有多少个线程正在读取资源。

关注二: 同步队列和等待队列的数据结构

AQS同步队列与等待队列

同步队列: 双向链表 等待(条件)队列: 单向链表

节点Node的数据: waitStatus等待状态(默认为0): 四种状态: -1 signal 未获取锁阻塞中(同步队列中) ; -2 condition 不满足条件进入等待区(等待队列中) ; -3 propagate(传播) 共享模式中 1 canceled 发生超时或中断 thread线程对象 prev前驱节点(同步队列) next后继节点(同步队列) nextWait等待队列的下一个节点

同步队列入队的过程:

1.节点入同步队列: 当前链表没有节点就进行初始化,然后将线程节点追加到队列中 2.线程阻塞: 1.先判断前驱节点是不是头节点,如果是那就再挣扎一下尝试获取锁,获取不成功会把当前 节点的等待状态设在前一个节点上:(队列是一个先进先出的数据结构,这样设计可以让当前节点在执行操作的时候就知道下一个节点需要做什么) 2.通过调用park阻塞线程

同步队列出队的过程:

1.unparkSuccessor(Node head) 1设置头结点的等待状态为初始值 CAS(head.waitStatus, 0) 2检测头节点的下一个节点并唤醒其中的线程 LockSupport.unpark(head.next.thread) 3被唤醒,判断前驱节点为头结点,尝试获取锁 2.头节点脱钩aquireQueued(Node node, int arg) 4获取锁成功,设置当前节点为head,使原head脱钩出队 5获取锁失败,阻塞自身,等下一下次被唤醒

等待队列节点的入队await()

①创建并添加新节点到等待队列 ②释放锁,唤醒同步队列的节点 ③被转移到同步队列前一直阻塞 LockSupport.park(this) ④重新尝试获取锁

等待队列节点的出队signal()/signalAll()

将等待队列的第一个节点转移到同步队列 ①firstWaiter指向下一个节点 ②首节点脱钩 ③将首节点转移到同步队列 检查首节点是否取消:设置同步状态为0 将首节点续接到同步队列 设置同步队列尾节点等待状态为-1 ④在操作中发现节点取消,则唤醒该节点 LockSupport.unpark(firstNode.thread) ⑤若使用signalAll,则循环上述操作 感悟:signalAll操作并没有直接唤醒线程,而是将线程节点从等待队列脱钩都,追加入同步队列,竞争锁(若发生意外,则直接唤醒unpark)

线程的等待与唤醒

LockSupport.park() LockSupport.unpark()

AQS是怎么支持公平和非公平策略?

AQS的底层支持闯入策略:

等待队列是先来先服务的,但是AQS支持可闯入策略,在高并发的情况下新来的线程和等待队列中的线程同时竞争锁,当新来线程竞争成功,就造成了非公平,大大提供了吞吐率

如何做一个公平锁

线程在tryAcquire的时候都要判断自己是否在等待队列中,不在的话就追加到等待队列中,让队首线程获取锁
链接:https://juejin.cn/post/7389209265946886196
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值