AQS简介及其常见实现

Gemini永久会员 40种基于AQS实现的常见同步工具及其简单实现思路 BooleanLock(布尔锁)@Override@Override// 其他Lock接口方法...OneShotLatch(一次性门闩)@Override1 : -1;@OverrideThreadGate(线程门)控制线程在特定条件下通过BoundedSemaphore(有界信号量)限制可用许可数量ReadWriteLockImpl(自定义读写锁)实现基本的读写锁功能Mutex(互斥锁)简单的互斥锁实现Latch(门闩抽象类)提供门闩的基础实现。 阅读详情

JAVA层面如何实现管程模型? synchronized、AQS两种实现

AQS

是什么

AQS是java.util.concurrent.locks包下的一个基础框架,用于构建锁和其他同步组件(如Semaphore、CountDownLatch等)。它简化了这些同步器的实现,提供了一个FIFO(先进先出)的等待队列,以及一个用于管理同步状态的原子性整数。可以把它理解为实现同步器的“脚手架”或“模板”。AQS 将复杂的线程管理逻辑隐藏起来,使开发者只需专注于具体的同步逻辑。AQS是jdk并发包java.util.concurrent下绝大部分工具类实现的基础

AQS具备的特性:

  • state(同步状态) state 属性来表示资源的状态
    • 它的具体含义由子类定义和实现。例如:

    • 在ReentrantLock中,state表示锁的持有计数(0表示未锁定,>0表示被锁定,且数值表示重入次数)。

    • 在Semaphore中,state表示剩余的许可证数量。

    • 在CountDownLatch中,state表示还需要等待的计数。

  •  FIFO 的等待队列,用于存放所有等待获取资源的线程
    • 双向链表
    • 类似于 Monitor 的 EntryList 条件变量来实现等待、唤醒机制,只不过是JAVA实现的
  • 支持多个条件变量
  • AQS的两种资源共享模式
    • 独占模式(Exclusive):资源一次只能被一个线程持有。例如:ReentrantLock。

    • 共享模式(Shared):资源可以被多个线程同时持有。例如:Semaphore, CountDownLatch。

具体实现

ReentrantLock-可重入锁

  • 模式:独占模式。

  • state的含义:表示锁的重入次数。当线程第一次获取锁时,state变为1;如果该线程再次获取锁(重入),state会递增。释放锁时,state递减,直到为0才表示锁完全释放。

  • 特点:支持公平锁和非公平锁(构造函数指定)。

    • 公平锁:严格按照FIFO顺序从等待队列中获取锁。

    • 非公平锁:新来的线程有机会“插队”直接尝试获取锁,可能比等待队列中的线程先拿到锁,吞吐量通常更高。

  • 条件变量:
package com.test.jucdemo.lock;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import lombok.extern.slf4j.Slf4j;

/**
 * @author 
 * 条件变量
 */
@Slf4j
public class ReentrantLockDemo6 {
    private static ReentrantLock lock = new ReentrantLock();
    private static Condition cigCon = lock.newCondition();
    private static Condition takeCon = lock.newCondition();

    private static boolean hashcig = false;
    private static boolean hastakeout = false;

    //送烟
    public void cigratee(){
        lock.lock();
        try {
            while(!hashcig){
                try {
                    log.debug("没有烟,歇一会");
                    // 前半段: 释放锁,进入条件队列,然后阻塞线程

                    //过渡阶段: 被其他调用singal/singalAll的线程唤醒 (前提:要在同步队列中)
                    // 调用singal/singalAll的线程:  条件队列转同步队列,
                    // 可以在释放锁的时候唤醒head的后续节点所在的线程

                    // 后半段: 获取锁( 如果有竞争,cas获取锁失败,还会阻塞),
                    // 释放锁(唤醒同步队列中head的后续节点所在的线程)
                    // 后半段的逻辑其实就是独占锁的逻辑
                    cigCon.await();

                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            log.debug("有烟了,干活");
        }finally {
            lock.unlock();
        }
    }

    //送外卖
    public void takeout(){
        lock.lock();
        try {
            while(!hastakeout){
                try {
                    log.debug("没有饭,歇一会");
                    takeCon.await();

                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            log.debug("有饭了,干活");
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        ReentrantLockDemo6 test = new ReentrantLockDemo6();
        new Thread(() ->{
            test.cigratee();
        }).start();

        new Thread(() -> {
            test.takeout();
        }).start();

        new Thread(() ->{
            lock.lock();
            try {
                hashcig = true;
                log.debug("唤醒送烟的等待线程");
                cigCon.signal();
            }finally {
                lock.unlock();
            }


        },"t1").start();

        new Thread(() ->{
            lock.lock();
            try {
                hastakeout = true;
                log.debug("唤醒送饭的等待线程");
                takeCon.signal();
            }finally {
                lock.unlock();
            }
        },"t2").start();
    }

}
  • 几点synchronized和ReentrantLock的区别:

synchronized是JVM层次的锁实现,ReentrantLock是JDK层次的锁实现;
synchronized的锁状态是无法在代码中直接判断的,但是ReentrantLock可以通过
ReentrantLock#isLocked判断;
synchronized是非公平锁,ReentrantLock是可以是公平也可以是非公平的;
synchronized是不可以被中断的,而ReentrantLock#lockInterruptibly方法是可以
被中断的;
在发生异常时synchronized会自动释放锁,而ReentrantLock需要开发者在finally
块中显示释放锁;
ReentrantLock获取锁的形式有多种:如立即返回是否成功的tryLock(),以及等待指
定时长的获取,更加灵活;
synchronized在特定的情况下对于已经在等待的线程是后来的线程先获得锁(回顾
一下sychronized的唤醒策略),而ReentrantLock对于已经在等待的线程是先来的线程
先获得锁;

ReentrantReadWriteLock(可重入读写锁)

  • 模式:内部有两把锁:读锁(共享)和写锁(独占)。

  • state的设计:一个int类型的state被巧妙拆分成两部分:

    • 高16位:表示读锁的持有数量。

    • 低16位:表示写锁的重入次数。

  • 特点:

    • 读写互斥:写锁被持有时,任何其他线程都无法获取读锁或写锁。

    • 读读共享:多个线程可以同时持有读锁。

    • 支持锁降级:一个线程在持有写锁的情况下,可以继续获取读锁,然后再释放写锁。这样就从写锁降级成了读锁。反之(锁升级)则不被允许。

Semaphore俗称信号量

  • 模式:共享模式。

  • state的含义:表示可用许可证(permits)的数量。

  • 工作方式:

    • acquire():获取一个许可证,state减1。如果无证可用,则线程阻塞。

    • release():释放一个许可证,state加1,并唤醒一个等待线程。

  • 用途:用于控制同时访问特定资源的线程数量,如数据库连接池、流量控制。

package com.test.jucdemo.lock;

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class SemaphoreTest2 {

    /**
     * 实现一个同时只能处理5个请求的限流器
     */
    private static Semaphore semaphore = new Semaphore(5);

    /**
     * 定义一个线程池
     */
    private static ThreadPoolExecutor executor = new ThreadPoolExecutor
            (10, 50, 60,
                    TimeUnit.SECONDS, new LinkedBlockingDeque<>(200));

    /**
     * 模拟执行方法
     */
    public static void exec() {
        try {
            //占用1个资源
            semaphore.acquire(1);
            //TODO  模拟业务执行
            System.out.println("执行exec方法");
            Thread.sleep(2000);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放一个资源
            semaphore.release(1);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        {
            for (; ; ) {
                Thread.sleep(100);
                // 模拟请求以10个/s的速度
                executor.execute(() -> exec());
            }
        }
    }
}

配合异常处理的样例代码

import java.util.concurrent.Semaphore;

public class SemaphoreInterruptExample {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(0); // 初始许可为0,表示没有可用许可
        Thread workerThread = new Thread(() -> {
            try {
                System.out.println("Worker thread is trying to acquire a permit.");
                semaphore.acquire(); // 尝试获取许可,这里会阻塞
                System.out.println("Worker thread acquired a permit.");
            } catch (InterruptedException e) {
                System.out.println("Worker thread was interrupted while waiting for a permit.");
                Thread.currentThread().interrupt(); // 恢复中断状态
            } finally {
                System.out.println("Worker thread is releasing the permit.");
                semaphore.release(); // 释放许可
            }
        });

        Thread interruptThread = new Thread(() -> {
            try {
                Thread.sleep(2000); // 等待2秒,让 workerThread 进入 acquire 的阻塞状态
                System.out.println("Interrupt thread is interrupting worker thread.");
                workerThread.interrupt(); // 中断 workerThread
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        workerThread.start();
        interruptThread.start();
    }
}

CountDownLatch

CountDownLatch(闭锁)是一个同步协助类,允许一个或多个线程等待,直到其他线程完成
操作集。

使用场景

一般用作多线程倒计时计数器,强制它们等待其他一组(CountDownLatch的初始化决定)任务执行完成。CountDownLatch的两种使用场景:场景1:让多个线程等待、场景2:让单个线程等待。

  • 让多个线程等待:模拟并发,让并发线程一起执行 (不常见)
package com.test.jucdemo.lock;

import java.util.concurrent.CountDownLatch;

/**
 * 让多个线程等待:模拟并发,让并发线程一起执行
 */
public class CountDownLatchTest {
    public static void main(String[] args) throws InterruptedException {

        CountDownLatch countDownLatch = new CountDownLatch(1);
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    //准备完毕……运动员都阻塞在这,等待号令
                    countDownLatch.await();
                    String parter = "【" + Thread.currentThread().getName() + "】";
                    System.out.println(parter + "开始执行……");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        Thread.sleep(2000);// 裁判准备发令
        countDownLatch.countDown();// 发令枪:执行发令
    }
}

  • 让单个线程等待:多个线程(任务)完成后,进行汇总合并(常见)
package com.test.jucdemo.lock;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 让单个线程等待:多个线程(任务)完成后,进行汇总合并
 */
public class CountDownLatchTest2 {
    public static void main(String[] args) throws Exception {
        CountDownLatch countDownLatch = new CountDownLatch(5);
        for (int i = 0; i < 5; i++) {
            final int index = i;
            new Thread(() -> {
                try {
                    Thread.sleep(1000 +
                            ThreadLocalRandom.current().nextInt(1000));
                    System.out.println(Thread.currentThread().getName()
                            + " finish task" + index);
                    countDownLatch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        // 主线程在阻塞,当计数器==0,就唤醒主线程往下执行。
        countDownLatch.await();
        System.out.println("主线程:在所有任务运行完成后,进行结果汇总");
    }
}

有没有可以改进的地方呢?

可以使用 CompletableFuture 类来改进!Java8 的 CompletableFuture 提供了很多对多线程友好的方法,使用它可以很方便地为我们编写多线程程序,什么异步、串行、并行或者等待所有线程执行完任务什么的都非常方便

package concurrent;
 
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
 
import java.util.concurrent.CompletableFuture;
 
public class TestCompletableFuture {
 
    public static void main(String[] args) {
        // T1
        CompletableFuture<Void> futureT1 = CompletableFuture.runAsync(() -> {
            System.out.println("T1 is executing. Current time:" + DateUtil.now());
            // 模拟耗时操作
            ThreadUtil.sleep(1000);
        });
        // T2
        CompletableFuture<Void> futureT2 = CompletableFuture.runAsync(() -> {
            System.out.println("T2 is executing. Current time:" + DateUtil.now());
            ThreadUtil.sleep(1000);
        });
 
        // 使用allOf()方法合并T1和T2的CompletableFuture,等待它们都完成
        CompletableFuture<Void> bothCompleted = CompletableFuture.allOf(futureT1, futureT2);
        // 当T1和T2都完成后,执行T3
        bothCompleted.thenRunAsync(() -> System.out.println("T3 is executing after T1 and T2 have completed.Current time:" + DateUtil.now()));
        // 等待所有任务完成,验证效果
        ThreadUtil.sleep(3000);
    }
}

上面的代码还可以继续优化,当任务过多的时候,把每一个 task 都列出来不太现实,可以考虑通过循环来添加任务。

//文件夹位置
List<String> filePaths = Arrays.asList(...)
// 异步处理所有文件
List<CompletableFuture<String>> fileFutures = filePaths.stream()
    .map(filePath -> doSomeThing(filePath))
    .collect(Collectors.toList());
// 将他们合并起来
CompletableFuture<Void> allFutures = CompletableFuture.allOf(
    fileFutures.toArray(new CompletableFuture[fileFutures.size()])
);

CyclicBarrier

  • 注意:CyclicBarrier的早期版本是基于ReentrantLock和Condition实现的,而非直接继承AQS,但它同样利用了AQS的思想。它是一个更高级的同步工具。

  • 工作方式:让一组线程到达一个屏障(同步点)时被阻塞,直到最后一个线程到达屏障,所有被屏障拦截的线程才会继续运行。

  • 与CountDownLatch的区别:

    • CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以重置,能重复使用(Cyclic的含义)。

    • CyclicBarrier还支持一个可选的Runnable任务,在所有线程到达屏障后执行。

字面意思回环栅栏,通过它可以实现让一组线程等待至某个状态(屏障点)之后再全部同
时执行。回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。

使用场景

CyclicBarrier 可以用于多线程计算数据,最后合并计算结果的场景

package concurrent;

import java.util.Set;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 栅栏与闭锁 CountDownLatch 的关键区别在于,所有的线程必须同时到达栅栏位置,才能继续执行。
 */
public class CyclicBarrierTest2 {

    //保存每个学生的平均成绩
    private ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String,Integer>();

    private ExecutorService threadPool= Executors.newFixedThreadPool(3);

    //  提供一个 barrierAction,合并多线程计算结果  
    private CyclicBarrier cb=new CyclicBarrier(3,()->{
        int result=0;
        Set<String> set = map.keySet();
        for(String s:set){
            result+=map.get(s);
        }
        System.out.println("三人平均成绩为:"+(result/3)+"分");
    });


    public void count(){
        for(int i=0;i<3;i++){
            threadPool.execute(new Runnable(){
                @Override
                public void run() {
                    //获取学生平均成绩
                    int score=(int)(Math.random()*40+60);
                    map.put(Thread.currentThread().getName(), score);
                    System.out.println(Thread.currentThread().getName()
                            +"同学的平均成绩为:"+score);
                    try {
                        // 阻塞直到指定的线程都调用此方法,继续执行
                        //执行完运行await(),等待所有学生平均成绩都计算完毕
                        cb.await();
                    } catch (InterruptedException | BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }


    public static void main(String[] args) {
        CyclicBarrierTest2 cb=new CyclicBarrierTest2();
        System.out.println("======第一次调用======");
        cb.count();
        System.out.println("======第二次调用======");
        cb.count();
    }
}

  • CyclicBarrier与CountDownLatch的区别:

CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()
方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可
以重置计数器,并让线程们重新执行一次

目录

AQS

是什么

AQS具备的特性:

AQS的两种资源共享模式

具体实现

ReentrantLock-可重入锁

ReentrantReadWriteLock(可重入读写锁)

Semaphore俗称信号量

配合异常处理的样例代码

CountDownLatch

使用场景

让多个线程等待:模拟并发,让并发线程一起执行 (不常见)

让单个线程等待:多个线程(任务)完成后,进行汇总合并(常见)

有没有可以改进的地方呢?

CyclicBarrier

使用场景

参考链接


CyclicBarrier还提供getNumberWaiting(可以获得CyclicBarrier阻塞的线程数量)、
isBroken(用来知道阻塞的线程是否被中断)等方法。


CountDownLatch会阻塞主线程,CyclicBarrier不会阻塞主线程,只会阻塞子线程。
CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点
CountDownLatch一般用于一个或多个线程,等待其他线程执行完任务后,再执
CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执

CyclicBarrier 还可以提供一个 barrierAction,合并多线程计算结果。


CyclicBarrier是通过ReentrantLock的"独占锁"和Conditon来实现一组线程的阻塞
唤醒的,而CountDownLatch则是通过AQS的“共享锁”实现

参考链接

docs/java/concurrent/java-concurrent-questions-03.md · java小皮匠/JavaGuide - Gitee.com

多线程 - Java实现并发的几种方法 【Java实现并发的几种方法】 阅读详情

相关推荐

易灵思FPGA实战:T35F324的PLL硬核配置全流程(附避坑指南)

本文详细解析了易灵思T35F324 FPGA中硬核PLL的配置全流程与核心避坑点。内容涵盖从架构理解、Interface Designer参数设置、VCO范围校验,到时钟网络冲突分析与动态重配置等实战环节,重点解决了引脚分配、资源约束和常见报错问题,为工程师提供了一套清晰可靠的配置指南。

u9v0w的博客 215

Java 并发(多线程)超详细

超级详细解析了 Java 多线程的应用等

qq_42689380的博客 1万+

FANUC机器人电弧跟踪功能深度解析:从电流采样原理到ROBOGUIDE仿真避坑指南

本文深度解析FANUC机器人电弧跟踪技术,从电流采样原理到ROBOGUIDE仿真避坑指南,详细介绍了电流波形分析、实时补偿机制及现场调试技巧。针对工业焊接中的常见问题,提供从底层原理到高阶应用的解决方案,帮助工程师优化自动化焊接质量。

weixin_31785177的博客 551

“深入理解Java多线程编程:并发控制与同步机制解析“

总结起来,深入理解Java多线程编程需要掌握并发控制和同步机制的原理和使用方法。通过合理地使用锁、原子操作、synchronized关键字等机制,可以保证多线程程序的正确性和性能。Java多线程编程是指在Java程序中使用多个线程来执行任务。多线程编程可以提高程序的并发性和性能,但也会带来一些并发控制和同步机制的问题。下面我将详细解析这些问题。除了上述机制外,Java还提供了一些高级的并发工具和数据结构,如线程池、阻塞队列等,它们能够帮助我们更方便地进行并发控制和同步。

jiheng1的博客 552

AI脸部替换Roop-Unleashed,一键整合包教程

Roop-Unleashed是一个无须训练模型的深度伪造工具,专为图像和视频的面部替换而设计。它通过简洁的浏览器界面提供用户友好且跨平台的使用体验,无论用户是业余爱好者还是专业人士,都能快速上手。它无需复杂的设置即可实现高效的处理和转换,使图像和视频的编辑变得更加轻松和便捷。

m0_72580657的博客 1万+

在树莓派上部署训练好的YOLO模型

.pt.模型转换为onnx格式的模型,树莓派上部署模型

pai_da_xing8的博客 3887

什么是Java中的多线程并发控制?如何解决?

Java中的多线程并发控制主要指的是在多线程环境下,对共享资源的访问和修改进行控制和协调,以防止数据不一致或其他并发问题的出现。

wudixiuluo的博客 1854

ANSYS/ANSYS Workbench生成mnf文件导入到Adams相关问题浅显解释

ANSYS/ANSYS Workbench生成mnf文件导入到Adams相关问题浅显解释。

weixin_45551870的博客 6984

Java并发控制 学习笔记1

正常的锁当一个线程拿不到共享资源时,会把该线程阻塞,等共享资源释放后,再唤醒该阻塞线程并进行调度;自旋锁当一个线程拿不到共享资源时,它就一直while循环来询问该资源释放了没有,会一直占用cpu资源。如果大多事务的执行时间很短,自旋锁空转一会就能拿到资源,就用自旋锁,这时如果采用阻塞/唤醒思路的话,调度的时间消耗会比较大。flag = 0;= 1);flag = 2;= 2);flag = 0;

又菜又爱玩 1283

弘玑RPA进阶攻略

01.弘玑RPA产品概要。02.设计器的安装与卸载。03.设计器特性与使用。

长安诗社社长@-梁瀚文- https://github.com/HevnChin https://gitee.com/HevnChin 3646

15、SQL Server查询优化与CPU负载管理

本文深入探讨了SQL Server查询优化与CPU负载管理的关键技术,包括强制连接类型的使用、键查找问题的解决、索引设计的最佳实践、高CPU负载的排查与优化,以及并行性的利弊与调整策略。通过优化查询逻辑、合理设计索引、监控与管理CPU资源,可以显著提升SQL Server的性能和稳定性。适用于数据库开发人员和DBA进行性能调优参考。

pz8901234的博客 77

什么是AQS及其原理

GitHub:https://github.com/JDawnF 1、AQS简介 AQS全名:AbstractQueuedSynchronizer,是并发容器J.U.C(java.lang.concurrent)下locks包内的一个类。它实现了一个FIFO(FirstIn、FisrtOut先进先出)的队列。底层实现的数据结构是一个双向链表。 Sync queue:同步队列,是一个双向链...

striveb的博客 4万+

Allegro技巧----相同模块复用实现快速布局

使用Allegro软件进行PCB Layout设计时,当电路图中有很多路相同的模块,使用模块复用的的操作方法,可以显著提高工作效率,同时也可以使PCB布局在整体上显得美观。 如图,有8个相同的ADC采样电路模块,它们在原理图中的电路也是一样的,对于这多个相同的电路模块,如果一个个元器件布局很明显做了很多重复机械的劳动,效率低下;但是强大的Allegro软件早就考虑到了这点,只需要在PCB中做好其中的一个,则其余相同的模块通过复用的方式,可以快速完成,方便省事还美观。 具体步骤: 1.首先完成一个模块的PC

sinat_15677011的博客 5655

java-AQS简介

一、什么是AQS AQS,在java.util.concurrent.locks包中,AbstractQueuedSynchronizer这个类是并发包中的核心,了解其他类之前,需要先弄清楚AQS。 AQS就是一个同步器,要做的事情就相当于一个锁,所以就会有两个动作:一个是获取,一个是释放。获取释放的时候该有一个东西来记住他是被用还是没被用,这个东西就是一个状态。如果锁被获取了,也就是被用了,还有很多其他的要来获取锁,总不能给全部拒绝了,这时候就需要他们排队,这里就需要一个队列。 AQS的核心思想是:

wwwzhouzy的专栏 1万+

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Lock简介与初识AQS

文章目录concurrent包的结构层次Lock简介Lock接口API初识AQSAQS的模板方法设计模式一个例子 concurrent包的结构层次 在针对并发编程中,Doug Lea大师为我们提供了大量实用,高性能的工具类,针对这些代码进行研究会让我们队并发编程的掌握更加透彻也会大大提升我们队并发编程技术的热爱。这些代码在java.util.concurrent包下。如下图,即为concurren...

ThinkWon的博客 1万+

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

什么是AQS

AQS ( Abstract Queued Synchronizer )是一个抽象的队列同步器,通过维护一个共享资源状态( Volatile Int State )和一个先进先出( FIFO )的线程等待队列来实现一个多线程访问共享资源的同步框架。

qq_40322236的博客 2万+

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

从ReentrantLock的实现看AQS的原理及应用

总第374篇2019年 第52篇AQS作为JUC中构建锁或者其他同步组件的基础框架,应用范围十分广泛,这篇文章会带着大家从可重入锁一点点揭开AQS的神秘面纱。前言Java中的大部分同步类...

美团技术团队 8484

AQS实现原理

AQS中维护了一个volatile int state(共享资源)和一个CLH队列。当state=1时代表当前对象锁已经被占用,其他线程来加锁时则会失败,失败的线程被放入一个FIFO的等待队列中,然后会被UNSAFE.park()操作挂起,等待已经获得锁的线程释放锁才能被唤醒。 我们拿具体场景来分析,假设同时有三个线程并发抢占锁,此时线程一抢占成功,线程二、三抢占失败,具体流程如下: 此时AQS内部数据结构为: 上图可以看到等待队列中的节点Node是一个双向链表,这里SIGNAL是No..

summer_fish的专栏 5543

什么是AQS?AQS有什么作用?常见的基于AQS的组件有哪些?

1.什么是AQS AQS队列同步器(AbstractQueuedSynchronizer),是用来构建锁或者其他同步组件的基础框架。 它使用了一个int的成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。 同步器的主要使用方式是继承,子类通过基础同步器并实现它的抽象方法来管理同步状态,在抽象方法的实现过程中免不了对同步状态进行更改,这时需要使用同步器提供的三个方法(getState()、setState(int newState)和compareAndSetState(int exp

weixin_46248981的博客 4049

AQS浅析及其实现类

AQS(AbstractQueuedSynchronizer),抽象队列同步器,AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它。 AQS的核心思想是如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并将共享资源设置为锁定状态;如果被请求的共享资源被占用,就需要一定的阻塞等待唤醒机制来保证锁分配,这个机制AQS是用CLH队列的变体实现的,即将暂时获取不到锁的线程加入到队列中。 CLH(Craig,Landin,a...

有个疙叫瘩儿的博客 877

Java中的AQS(一)AQS简介

    队列同步器AbstractQueuedSynchronizer,是用来构建锁或者其他同步组件的基础框架,它使用一个int成员表示同步状态,通过内部的FIFO队列来完成资源获取线程的排序工作。一、AQS的设计    AQS的设计是基于模板方法模式的,也就是说,使用者需要继承AQS并重写指定的方法,随后将AQS组合在自定义同步组件的实现中,并调用AQS提供的模板方法,而这些模板方法将会调用使用...

yanghan1222的博客 8728

AQS原理简介以及利用AQS简单实现一个共享锁

AQS 指AbstractQueuedSynchronizer类。 AQS是java中管理“锁”的抽象类,锁的许多公共方法都是在这个类中实现。AQS是独占锁(例如,ReentrantLock)和共享锁(例如,Semaphore)的公共父类。AQS也被称为队列同步器,是用来构建锁或者其他同步组件的基础框架。 使用一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。 ...

weixin_42735356的博客 749

一文搞懂AQS及其组件的核心原理

前言 JDK1.5以前只有synchronized同步锁,并且效率非常低,因此大神Doug Lea自己基于Java写了一套并发框架,这套框架的核心就在于AbstractQueuedSynchronizer类(即AQS),性能非常高,所以被引入JDK包中,即JUC。那么AQS是如何做到高性能的呢?本篇就是对AQS及其相关组件进行分析,了解其原理,并领略大神的优美而又精简的代码。 AbstractQueuedSynchronizer AQS是JUC下最核心的类,没有之一,其它的Lock以及并发控制类都是基于这个

夜勿语的博客 3254

什么是AQS锁,有哪些常见的AQS锁

AQS提供了一种基于FIFO等待队列的机制,用于管理线程的获取和释放资源的顺序,并提供了一些模板方法供子类实现具体的同步策略。AQS锁是基于AQS框架实现的锁,它是一种独占锁,即同一时间只允许一个线程获取锁。AQS锁是基于AQS框架实现的锁,它是一种独占锁,即同一时间只允许一个线程获取锁。它常用于分阶段的任务并行执行。当一个线程尝试获取锁时,如果锁是可用的(没有被其他线程持有),则该线程直接获取锁,并将锁状态设置为已获取。当持有锁的线程释放锁时,AQS会从等待队列中选择一个线程,并将锁的所有权交给该线程。

Li2992673708的博客 612
上一篇: 并发-CAS及其实现juc.atomic
下一篇: 阻塞队列简介及常见场景
Learning_foolish
博客等级 码龄9年 14粉丝 63原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值