天道酬勤,学无止境

AQS

【Java技术探索】深入分析AQS的工作原理(前传)

来源:https://blog.51cto.com/alex4dream/2778642

2021-06-02 10:12:16    分类:博客    AQS   juc   java   Java技术专题系列

谈Java多线程离不开的AQS,听说滴滴考了这块

前言 如果你想深入研究Java并发的话,那么AQS一定是绕不开的一块知识点,Java并发包很多的同步工具类底层都是基于AQS来实现的,比如我们工作中经常用的Lock工具ReentrantLock、栅栏CountDownLatch、信号量Semaphore等,而且关于AQS的知识点也是面试中经常考察的内容,所以,无论是为了更好的使用还是为了应付面试,深入学习AQS都很有必要。 CAS是乐观锁的一种思想,它假设线程对资源的访问是没有冲突的,同时所有的线程执行都不需要等待,可以持续执行。如果有冲突的话,就用比较+交换的方式来检测冲突,有冲突就不断重试。CAS的全称是Compare-and-Swap,也就是比较并交换,它包含了三个参数:V,A,B,V表示要读写的内存位置,A表示旧的预期值,B表示新值,当执行CAS时,只有当V的值等于预期值A时,才会把V的值改为B,这样的方式可以让多个线程同时去修改,但也会因为线程操作失败而不断重试,对CPU有一定程序上的开销。AQS简介本文主角正式登场。AQS,全名AbstractQueuedSynchronizer,是一个抽象类的队列式同步器,它的内部通过维护一个状态volatile int state(共享资源),一个FIFO线程等待队列来实现同步功能。state用关键字volatile修饰,代表着该共享资源的状态一更改就能被所有线程可见

2021-06-02 01:21:32    分类:博客    java   程序员   AQS

AQS源码分析--jdk1.8

JDK1.8 ArrayList源码分析--jdk1.8LinkedList源码分析--jdk1.8HashMap源码分析--jdk1.8AQS源码分析--jdk1.8ReentrantLock源码分析--jdk1.8 AbstractQueuedSynchronizer概述   1. AQS是一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架。  2. AQS提供了双向链表。  3. AQS分为共享模式和独占模式。  4.AQS基于volatile内存可见性和CAS原子性操作实现线程间通信操作。 AbstractQueuedSynchronizer数据结构   数据结构是集合的精华所在,数据结构往往也限制了集合的作用和侧重点,了解各种数据结构是我们分析源码的必经之路。  AQS的数据结构如下:双向链表    AQS实现共享资源的访问控制基础:     1.state字段,即同步器状态字段。用于共享资源的访问控制     2.CLH队列,FIFO等待队列,存放竞争失败的线程。通常CLH队列是一个自旋队列,AQS以阻塞的方式实现     CLH队列的使用: CLH扫盲 自旋锁学习了解自旋锁之前先回顾一下互斥锁 互斥锁 线程在获取互斥锁的时候,如果发现锁已经被其它线程占有,那么线程就会惊醒休眠,然后在适当的时机(比如唤醒)在获取锁。 自旋锁 那么自旋锁顾名思义就是“自旋

2021-06-02 01:01:14    分类:博客    AQS   AQS源码分析   AQS并发   java

ReentrantLock (重入锁) 源码浅析

一、ReentrantLock简介ReentrantLock重入锁,顾名思义,就是支持重入的锁,它表示能够支持一个线程对资源的重复加锁;我们之前学习过Synchronized锁,它也是支持重入的一种锁,参考我的另一篇Synchronized 锁的实现原理与应用,Synchronized支持隐式的重入锁,比如递归方法,在方法运行时,执行线程在获取到了锁之后仍能连续多次地获取锁;ReentrantLock虽然不能隐式重入,但是获取到锁的线程多次调用lock方法,不会阻塞进入同步队列;除此之外在获取锁时支持公平或者非公平的选择。二、主要成员和结构图①、ReentrantLock关系图②、Sync是ReentrantLock的内部类,继承AQS③、FairSync公平的锁实现,也是ReentrantLock的内部类,继承Sync④、NonfairSync非公平的锁实现,也是ReentrantLock的内部类,继承Sync 三、主要的方法分析一些常用方法,不会介绍AQS,AQS的一些方法参考我的这一篇文章①、构造方法,我们可以看出默认的无参是非公平锁,有参构造true表示公平,false表示非公平。 // 无参 public ReentrantLock() { sync = new NonfairSync(); } // 有参 public ReentrantLock(boolean

2021-06-02 00:57:40    分类:博客    reentrantlock   AQS   Java 并发

AbstractQueuedSynchroizer(AQS) 同步器详解详解

一、什么是同步器同步器是用来构建锁或者其他同步组件的基础框架,它使用一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作,它能实现大部分的同步需求。同步器是实现锁的关键,在锁的实现中聚合同步器,利用同步器实现锁的语义。可以这样理解二者的关系:锁是面向使用者的,它定义了使用者与锁交互的接口(比如可以允许两个线程的并行访问),隐藏了实现细节;同步器面向的是锁的实现者,它简化了锁的实现方式,屏蔽了状态管理、线程的排队、等待与唤醒等底层操作。锁和同步容器很好地隔离了使用者和实现者所需要关注的领域。二、同步器的基本成员(介绍常用的类好方法)Node 是AQS的内部类构成AQS队列的一种数据结构。 成员变量 作用 waitStatus 记录节点的等待状态。包括如下状态:① CANCELLED,值为1,由于同步队列中等待线程超时或者被中断,需要从同步队列中取消等待,节点进入该状态将不会变化。② SIGNAL值为-1,后继节点的线程处于等待状态,而当前线程如果释放了同步状态或者取消,将会通知后继节点,使得后继节点得以运行。③ CONDITION值为-2,节点在等待队列中,节点等待在Condtion上,当其他线程对Condtion调用了signal方法后,该节点将会从等待队列中转移到同步队列中,加入到对同步状态的获取中。④ PROPAGATE值为-3

2021-06-02 00:57:33    分类:博客    AQS   AbstractQueuedSynch   Java 并发

JAVA基础学习之-AQS的实现原理分析

AbstractQueuedSynchronizer是JUC的核心框架,其设计非常精妙。 使用了Java的模板方法模式。 首先试图还原一下其使用场景:对于排他锁,在同一时刻,N个线程只有1个线程能获取到锁;其他没有获取到锁的线程被挂起放置在队列中,待获取锁的线程释放锁后,再唤醒队列中的线程。 线程的挂起是获取锁失败时调用Unsafe.park()方法;线程的唤醒是由其他线程释放锁时调用Unsafe.unpark()实现。由于获取锁,执行锁内代码逻辑,释放锁整个流程可能只需要耗费几毫秒,所以很难对锁的争用有一个直观的感受。下面以3个线程来简单模拟一下排他锁的机制。 import sun.misc.Unsafe; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.concurrent.locks.LockSupport; public class AQSDemo { private static final Unsafe unsafe = getUnsafe(); private static final long stateOffset; private static Unsafe getUnsafe() { try { Field

2021-06-02 00:54:12    分类:博客    java   AQS   多线程   java

Java并发编程(5)- J.U.C之AQS及其相关组件详解

J.U.C之AQS-介绍 Java并发包(JUC)中提供了很多并发工具,这其中,很多我们耳熟能详的并发工具,譬如ReentrangLock、Semaphore,而它们的实现都用到了一个共同的基类--AbstractQueuedSynchronizer(抽象队列同步器),简称AQS。 AQS是JDK提供的一套用于实现基于FIFO等待队列的阻塞锁和相关的同步器的一个同步框架,它使用一个int类型的volatile变量(命名为state)来维护同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。 AbstractQueuedSynchronizer中对state的操作是原子的,且不能被继承。所有的同步机制的实现均依赖于对改变量的原子操作。为了实现不同的同步机制,我们需要创建一个非共有的(non-public internal)扩展了AQS类的内部辅助类来实现相应的同步逻辑。 AbstractQueuedSynchronizer并不实现任何同步接口,它提供了一些可以被具体实现类直接调用的一些原子操作方法来重写相应的同步逻辑。AQS同时提供了独占模式(exclusive)和共享模式(shared)两种不同的同步逻辑。一般情况下,子类只需要根据需求实现其中一种模式,当然也有同时实现两种模式的同步类,如ReadWriteLock。 使用AQS能简单且高效地构造出应用广泛的大量的同步器

2021-06-02 00:45:04    分类:博客    juc   AQS   并发工具包   java

Java并发AQS详解

一、概述  谈到并发,不得不谈ReentrantLock;而谈到ReentrantLock,不得不谈AbstractQueuedSynchronizer(AQS)!  类如其名,抽象的队列式的同步器,AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock/Semaphore/CountDownLatch...。  以下是本文的目录大纲:概述框架源码详解简单应用  若有不正之处,请谅解和批评指正,不胜感激。二、框架  它维护了一个volatile int state(代表共享资源)和一个FIFO线程等待队列(多线程争用资源被阻塞时会进入此队列)。这里volatile是核心关键词,具体volatile的语义,在此不述。state的访问方式有三种:getState()setState()compareAndSetState()  AQS定义两种资源共享方式:Exclusive(独占,只有一个线程能执行,如ReentrantLock)和Share(共享,多个线程可同时执行,如Semaphore/CountDownLatch)。  不同的自定义同步器争用共享资源的方式也不同。自定义同步器在实现时只需要实现共享资源state的获取与释放方式即可,至于具体线程等待队列的维护(如获取资源失败入队/唤醒出队等),AQS已经在顶层实现好了

2021-06-01 23:34:39    分类:博客    多线程   AQS   java

死磕 java同步系列之AQS终篇(面试)

AQS的定位? AQS运用的设计模式? AQS的重要组成部分? AQS的总体流程?问题(1)AQS的定位?(2)AQS的重要组成部分?(3)AQS运用的设计模式?(4)AQS的总体流程?简介AQS的全称是AbstractQueuedSynchronizer,它的定位是为Java中几乎所有的锁和同步器提供一个基础框架。在之前的章节中,我们一起学习了ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch的源码,今天我们一起来对AQS做个总结。状态变量stateAQS中定义了一个状态变量state,它有以下两种使用方法:(1)互斥锁当AQS只实现为互斥锁的时候,每次只要原子更新state的值从0变为1成功了就获取了锁,可重入是通过不断把state原子更新加1实现的。(2)互斥锁 + 共享锁当AQS需要同时实现为互斥锁+共享锁的时候,低16位存储互斥锁的状态,高16位存储共享锁的状态,主要用于实现读写锁。互斥锁是一种独占锁,每次只允许一个线程独占,且当一个线程独占时,其它线程将无法再获取互斥锁及共享锁,但是它自己可以获取共享锁。共享锁同时允许多个线程占有,只要有一个线程占有了共享锁,所有线程(包括自己)都将无法再获取互斥锁,但是可以获取共享锁。AQS队列AQS中维护了一个队列,获取锁失败(非tryLock()

2021-05-18 18:32:34    分类:博客    java   AQS

死磕 java同步系列之AQS起篇

AQS是什么? AQS的定位? AQS的实现原理? 基于AQS实现自己的锁?问题(1)AQS是什么?(2)AQS的定位?(3)AQS的实现原理?(4)基于AQS实现自己的锁?简介AQS的全称是AbstractQueuedSynchronizer,它的定位是为Java中几乎所有的锁和同步器提供一个基础框架。AQS是基于FIFO的队列实现的,并且内部维护了一个状态变量state,通过原子更新这个状态变量state即可以实现加锁解锁操作。本章及后续章节的内容理解起来可能会比较晦涩,建议先阅读彤哥上一章的内容【死磕 java同步系列之自己动手写一个锁Lock】。核心源码主要内部类static final class Node { // 标识一个节点是共享模式 static final Node SHARED = new Node(); // 标识一个节点是互斥模式 static final Node EXCLUSIVE = null; // 标识线程已取消 static final int CANCELLED = 1; // 标识后继节点需要唤醒 static final int SIGNAL = -1; // 标识线程等待在一个条件上 static final int CONDITION = -2; // 标识后面的共享锁需要无条件的传播(共享锁需要连续唤醒读的线程) static

2021-05-18 18:31:45    分类:博客    java   AQS