AQS抽象的队列式同步器

常问问题  整理于网络

参考  https://segmentfault.com/a/1190000017372067 

推荐确实写的不错

J.U.C

简单解释一下J.U.C,是JDK中提供的并发工具包,java.util.concurrent。里面提供了很多并发编程中很常用的实用工具类,比如atomic原子操作、比如lock同步锁、fork/join等。

AQS

AQS,队列同步器 AbstractQueuedSynchronizer的简写,JDK1.5引入的,是用来构建锁或者其他同步组件的基础框架,它使用了一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。

AQS是一个抽象类,主要是通过继承的方式来使用,它本身没有实现任何的同步接口,仅仅是定义了同步状态的获取以及释放的方法来提供自定义的同步组件。

核心数据结构:双向链表 + state(锁状态)

底层操作:CAS


最基本的功能:获取锁,释放锁。其中获取锁应该是先判断当前状态是否可以获取,如果不可以获取则处于阻塞状态,释放应该是释放后修改状态,让其他线程能够得到该锁(唤醒其他线程)

AQS是将每一条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node),来实现锁的分配。

从使用层面来说,AQS的功能分为两种:独占和共享

独占锁,每次只能有一个线程持有锁,比如前面给大家演示的ReentrantLock就是以独占方式实现的互斥锁

共享锁,允许多个线程同时获取锁,并发访问共享资源,比如ReentrantReadWriteLock

用大白话来说,AQS就是基于CLH队列,用volatile修饰共享变量state,线程通过CAS去改变状态符,成功则获取锁成功,失败则进入等待队列,等待被唤醒。

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

**注意:AQS是自旋锁:**在等待唤醒的时候,经常会使用自旋(while(!cas()))的方式,不停地尝试获取锁,直到被其他线程获取成功

实现了AQS的锁有:自旋锁、互斥锁、读锁写锁、条件产量、信号量、栅栏都是AQS的衍生物



你可能感兴趣的:(AQS抽象的队列式同步器)