Java JUC并发 AbstractQueuedSynchronizer学习
来源:互联网 发布:江恩轮软件下载 编辑:程序博客网 时间:2024/06/04 19:47
前言
java.util.concurrent包(简称JUC)相比大家都应该很熟悉了。JUC包含许多线程安全、测试良好、高性能的并发构建块,之前一直没有研究过其核心锁的机制。前些日子,使用到了countDownLatch,没事点开了其源码,发现其核心功能是由AbstractQueuedSynchronizer的一个内部子类Syn实现的,进而发现在JUC中如ReentrantLock等很多常用类都实现了AbstractQueuedSynchronizer,AbstractQueuedSynchronizer为其实现了并发控制的功能。下面就详细分析一下AbstractQueuedSynchronizer。
AbstractQueuedSynchronizer 分析
AbstractQueuedSynchronizer 源码实现推荐去看
深度解析Java8 – AbstractQueuedSynchronizer的实现分析(上)
深度解析Java8 – AbstractQueuedSynchronizer的实现分析(下)
这片博客已经写的十分详细明了,珠玉在前就不再赘述了。我画了一下ReentrantLock 获取锁和释放锁的流程图,会放在这篇文章最后,希望可以在AQS看源码的时候有所帮助。在这里就之讲述一下我理解的AQS。
AbstractQueuedSynchronizer(简称AQS)核心思想就是通过一个共享变量同步状态,通过队列管理阻塞线程。
其中AQS中状态变量由各个子类定义管理,AQS重点提供队列的管理,线程的唤醒和挂起。
状态变量
AQS 使用一个 volatile修饰的int型变表示。一般情况下,状态变量如果为0,则表示锁尚未被获取到。在CountDownLatch 值为构造方法传入的数值,当countDown调用是,状态就会减一,直到状态变量为0,则唤醒阻塞队列中的线程。而ReentrantLock中由于是互斥锁,仅有0,1取值,表示锁是否已经获取:
/** * Returns the current value of synchronization state. * This operation has memory semantics of a {@code volatile} read. * @return current state value */ protected final int getState() { return state; } /** * Sets the value of synchronization state. * This operation has memory semantics of a {@code volatile} write. * @param newState the new state value */ protected final void setState(int newState) { state = newState; } /** * Atomically sets synchronization state to the given updated * value if the current state value equals the expected value. * This operation has memory semantics of a {@code volatile} read * and write. * * @param expect the expected value * @param update the new value * @return {@code true} if successful. False return indicates that the actual * value was not equal to the expected value. */ protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update); }
compareAndSetState是java Unsafe提供的CAS方法,保证了其安全性。在线程获取锁时,就会尝试使用这个方法更新状态位。
阻塞线程队列
前面说过,没有获取到锁的线程就会被放入一个队列中。AQS内部维护着一个FIFO的CLH队列,所以AQS并不支持基于优先级的同步策略。队列中的每个线程结点只要等待其前继释放锁就可以了。在这个对列中head节点时一个空节点。
Node节点中还有一个waitStatus的变量,用来描述节点的状态。
AQS的队列中,在有并发时,肯定会存取一定数量的节点,每个节点[G4] 代表了一个线程的状态,有的线程可能“等不及”获取锁了,需要放弃竞争,退出队列,有的线程在等待一些条件满足,满足后才恢复执行(这里的描述很像某个J.U.C包下的工具类,ReentrankLock的Condition,事实上,Condition同样也是AQS的子类)等等,总之,各个线程有各个线程的状态,但总需要一个变量来描述它。
waitStatus由四个取值:
/** waitStatus value to indicate thread has cancelled */ static final int CANCELLED = 1; /** waitStatus value to indicate successor's thread needs unparking */ static final int SIGNAL = -1; /** waitStatus value to indicate thread is waiting on condition */ static final int CONDITION = -2; /** * waitStatus value to indicate the next acquireShared should * unconditionally propagate */ static final int PROPAGATE = -3;
表示了:节点取消,节点等待触发,节点等待条件,节点状态需要向后传播。只有前一个节点时SIGNAL的当前节点才会被挂起。
线程的阻塞/唤醒
AQS并没有使用java线程提供的wait/notify 阻塞/唤醒线程,它通过了LockSupport.park() 和 LockSupport.unpark() 的本地方法来实现线程的阻塞和唤醒。实际上这两个方法也是对java Unsafe的一个封装。Unsafe之后有机会在讲。
独占锁的获取和释放流程
获取
释放
- Java JUC并发 AbstractQueuedSynchronizer学习
- Java并发学习(三)-AbstractQueuedSynchronizer
- JUC包之AbstractQueuedSynchronizer源码学习
- Java并发包--AbstractQueuedSynchronizer
- java并发之AbstractQueuedSynchronizer
- 【Java并发】详解 AbstractQueuedSynchronizer
- java 并发包-AbstractQueuedSynchronizer
- Java并发之AbstractQueuedSynchronizer分析
- java并发编程之AbstractQueuedSynchronizer
- Java并发编程(一)--AbstractQueuedSynchronizer
- JUC AbstractQueuedSynchronizer原理解析
- [Java并发] AbstractQueuedSynchronizer实现(一)
- 读JAVA并发包之AbstractQueuedSynchronizer
- Java多线程并发器之AbstractQueuedSynchronizer分析
- 【Java并发】- AbstractQueuedSynchronizer详解(AQS)
- Java 并发 ---AbstractQueuedSynchronizer(同步器)-独占模式
- Java 并发 ---AbstractQueuedSynchronizer-共享模式与Condition
- JUC - AbstractQueuedSynchronizer(AQS) 源码分析
- 什么是猴子补丁(monkey patch)
- 'utf8' codec can't decode byte --python
- 大数据量高并发访问SQL优化方法
- AndroidStudio配置NDK/JNI开发环境细节
- VerifyError: Error #1014: 无法找到类 mx.containers::Panel
- Java JUC并发 AbstractQueuedSynchronizer学习
- 实现H5的拖放
- 最长回文子串
- 流计算
- SQLite数据库存储
- java 与 JS 交互
- Vue-cli+router+webpack
- 公网与内网以及NAT关系
- Javascript 数据类型