JUC源码解析——AQS

在java.util.concurrent包(下称j.u.c包)中,大部分的同步器(例如锁,屏障等等)都是基于AbstractQueuedSynchronizer(下称AQS类)这个类来构建的;它是个抽象的FIFO队列式的同步器,AQS定义了一套多线程访问共享资源的同步器框架。


J.U.C包下的同步器的实现都主要依赖于以下几个功能:

  • 内部同步状态的管理
  • 同步状态的更新和检查操作
  • 且至少有一个方法会导致调用线程在同步状态被获取时阻塞,以及在
    其他线程改变这个同步状态时解除线程的阻塞

而AQS就实现了以上功能,供其他同步器使用。
所有同步器都有两个基本方法,acquire,release。acquire操作阻塞调用的线程,直到或除非同步状态允许其继续执行。而release操作则是通过某种方式改变同步状态,使得一或多个被acquire阻塞的线程继续执行。(不用同步器命名不同Lock.lock,Semaphore.acquire,CountDownLatch.await...)

之前提过Synchronized内置锁,JVM对其进行了许多优化,其性能已经比ReentrentLock更好,但是常规的JVM锁优化策略并不适用于严重依赖于J.U.C包的典型多线程服务端应用。
大部分情况下,特别在同步器有竞争的情况下,稳定地保证其效率才是J.U.C包的主要目标。

同步器的acquire与release

acquire

while(同步状态不允许acquire){
        放入队列  if  没有进队;
        依具体需求来决定是否阻塞当前线程;
}
出队 if 已入对;

release

更新同步状态;
if(状态允许被阻塞线程acquire){
      解除一个或多个队列里的阻塞线程;
}

要实现上述功能需要三个基本组建的相互协作:

  • 同步状态的原子性管理
  • 线程的阻塞与解除阻塞
  • 队列的管理

同步状态
AQS用单个32位int值 state 来表示同步状态
阻塞
利用LockSupport来阻塞/唤醒线程

队列:

无法获取执行资格的线程会构建一个节点Node加入队列,AQS中使用的是CLH队列:CLH同步队列是一个FIFO双向队列,AQS依赖它来完成同步状态的管理,当前线程如果获取同步状态失败时,AQS则会将当前线程以及等待状态等信息构造成一个节点(Node)并将其加入到CLH同步队列,同时会阻塞当前线程,当同步状态释放时,会把首节点唤醒,使其再次尝试获取同步状态。对于队列中的某个节点来说,它只需要通过判断其前一个节点的状态信息来

关于队列的节点Node:5条属性,分别是wateStatus 、prev、next、thread、nextWater。

1,其中 prev,next用于构建双向链表,thread 指向节点对应的线程。

2,waitStatus表示当前被封装成Node结点的等待状态,共有4种取值CANCELLED、SIGNAL、CONDITION、PROPAGATE。

CANCELLED:值为1,在同步队列中等待的线程等待超时或被中断,需要从同步队列中取消该Node的结点,其结点的waitStatus为CANCELLED,进入该状态后的结点将会被删除。

SIGNAL:值为-1,表明该节点之后有节点在阻塞,当该节点被唤醒或删除后会必须唤醒其后继节点

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值