一、j.u.c简介
在说主题AQS之前,我们有必要先来说一下J.U.C
顾名思义J.U.C就是java.util.concurrent,java并发工具包。由我们的并发大师老爷子Doug Lea亲自操刀完成。而在这个包里,包含了我们大名鼎鼎的Lock、ConrurrentHashMap、CountDownLatch、Executor、LinkedBlockingQueue、ThreadPoolExecutor等重要的处理并发的类或者接口。当然,这些只是我听说过的一些。(此处应该有一个笑哭的表情),后续我将会带大家一一解读这些重要的并发工具。
废话不多说,让我们一步一步剥丝抽茧,解开AQS的神秘面纱。
二、AQS
1.AQS概要
AQS,全程AbstractQueuedSynchronizer--抽象队列同步器,他诞生于JDK1.5,是java中关于线程、同步的基础组件。如果对原文感兴趣的话,可以参见大师的原文:J.U.C Synchronizer Framework。既然作为基础组件,那么它便存在了大量的应用场景。
1.1 AQS应用场景
在此处,我们以可重入锁ReentrantLock来举例,说明AQS的内在原理。ReentrantLock关系类图如下:
1 package com.jarluo.AQS; 2 3 import java.util.concurrent.locks.Lock; 4 import java.util.concurrent.locks.ReentrantLock; 5 6 /** 7 * @desc AQS应用场景之可冲入锁ReentrantLock 8 * @author jar luo 9 * @time 2019.5.21 10 */ 11 public class ReentrantLockDemo { 12 13 static Lock lock = new ReentrantLock(); 14 15 public static void main(String[] args) { 16 lock.lock(); 17 try { 18 System.out.println("AQS应用场景之可冲入锁ReentrantLock"); 19 } finally { 20 lock.unlock(); 21 } 22 } 23 }
从上面的代码,我们可以看出,AQS应用起来还是很简单的,但是我们从关系类图中可以看到在ReentrantLock中维护了一个Sync内部类,同时Sync有两个子类,分别是NonFairSync和FairSync。此处我们主要对NonFairSync进行追踪(FairSync更加简单一些),可以得到以下时序图:
通过观察AQS源码发现,AQS 包含了以下几种核心技术点:
1.1 state
1.2 cas原子方法
1.3 自旋锁
1.4 CLH变种队列
沿着volitile状态管理-CAS原子操作-自旋锁-CLH队列进行展开
2.锁的基本要素
2.1 一个共享的数据来记录状态
二、Lock
0.synchronized和ReentrantLock的区别
1.关键字、一个是J.U.C
2.释放
局限性:不够灵活,锁释放要么执行完,要么出异常。
1.Lock是什么
1.1Lock是一个interface。
1.2Lock 提供了获得锁和释放锁的方法
2.重入锁
2.1 ReentrantLock 重入互斥锁--表示可以重新进入的锁。
2.1.1唯一实现了Lock接口的一个类。
lock.lock(),增加重入次数
synchronized也支持重入。
代码示例:
2.1.2 当多个线程竞争锁的时候,其他线程怎么办?
阻塞
2.2 ReentrantReadWriteLock --重入读写锁
读->读 是共享的
读->写 互斥
写->写 互斥
适用场景:读多写少的场景。
代码示例:
三、AQS--抽象队列同步器
1.概念:同步工具
2.功能:
2.1独占->互斥
2.2共享->读读
3.基本实现:
用双向链表去维护等待获得锁的线程对象
Node节点 上节点 下节点 线程
状态(state):锁标记
0是无锁状态
>=1是有锁状态(表示可以重入)
4.CAS
偏移量 cas(obj,offset,expect,update)
乐观锁
本地方法:
四、Sync
1.非公平锁--NonfairSync
允许插队
2.公平锁--FairSync
不允许插队
五、关系图
时序图