JUC之AQS第二部分:共享锁部分

JUC框架 源码解析系列文章目录 JDK8 前言 笔者在接下来这段时间将对JUC框架内的重点内容进行深度解析,由于内容颇多,需要分成多篇文章,所以在这里列一个目录,方便大家翻阅。 目录 JUC框架的基础是CAS和自旋,而CAS则是利用Unsafe类提供的CAS操作,而原子类则依靠于CAS和自旋。下面几篇文章从源码分析JUC框架内的几个重要的原子类。 JUC AtomicInteger源码解析 JDK8 JUC AtomicIntegerArray源码解析 JDK8 JUC AtomicStampedReference源码解析 JDK8 AQS(A 阅读详情

AQS有两种模式,一种是独占模式,一种是共享模式。这篇文章是关于共享模式的原理。

  1. 当线程调用acquireShared()申请获取锁资源时,如果成功,则进入临界区。
  2. 当获取锁失败时,则创建一个共享类型的节点并进入一个FIFO等待队列,然后被挂起等待唤醒。
  3. 当队列中的等待线程被唤醒以后就重新尝试获取锁资源,如果成功则唤醒后面还在等待的共享节点并把该唤醒事件传递下去,即会依次唤醒在该节点后面的所有共享节点,然后进入临界区,否则继续挂起等待。

tryAcquireShared应该在子类实现,返回值小于0表示获取锁失败,需要进入等待队列。其二、如果返回值等于0表示当前线程获取共享锁成功,但它后续的线程是无法继续获取的,也就是不需要把它后面等待的节点唤醒。最后、如果返回值大于0,表示当前线程获取共享锁成功且它后续等待的节点也有可能继续获取共享锁成功,也就是说此时需要把后续节点唤醒让它们去尝试获取共享锁。

	
    public final void acquireShared(int arg) {

        if (tryAcquireShared(arg) < 0)//
            doAcquireShared(arg);
    }

    private void doAcquireShared(int arg) {
        final Node node = addWaiter(Node.SHARED);//向队列中添加共享节点
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                //发现自己是老二了,赶快去抢号
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {//当前节点获取锁成功,并可能可以向后传递
                        setHeadAndPropagate(node, r);//唤醒后续节点,同时将head节点置为当前的节点。
                        p.next = null; // help GC
                        if (interrupted)
                            selfInterrupt();
                        failed = false;
                        return;
                    }
                }
                //和独占锁的逻辑一样
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

##release

    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {//tryReleaseShared应该在子类中实现
            doReleaseShared();
            return true;
        }
        return false;
    }
   
    private void doReleaseShared() {
        /*
         * Ensure that a release propagates, even if there are other
         * in-progress acquires/releases.  This proceeds in the usual
         * way of trying to unparkSuccessor of head if it needs
         * signal. But if it does not, status is set to PROPAGATE to
         * ensure that upon release, propagation continues.
         * Additionally, we must loop in case a new node is added
         * while we are doing this. Also, unlike other uses of
         * unparkSuccessor, we need to know if CAS to reset status
         * fails, if so rechecking.
         */
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    } 

##Semaphore具体实现的例子

    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);//请求一个令牌
    }

    //公平锁版本(需要检查有没有前面的排队节点)
    protected int tryAcquireShared(int acquires) {
        for (;;) {
            if (hasQueuedPredecessors())
                return -1;
            int available = getState();
            int remaining = available - acquires;
            if (remaining < 0 ||
                compareAndSetState(available, remaining))
                return remaining;
        }
    }
	
	//不公平版本(不需要检查有没有排序的节点)
    final int nonfairTryAcquireShared(int acquires) {
       for (;;) {
           int available = getState();
           int remaining = available - acquires;
           if (remaining < 0 ||
               compareAndSetState(available, remaining))
               return remaining;
       }
   }
c转c++——蓝桥杯 在这里,`int &i` 表示 `i` 是一个整型的引用变量,而不是一个拷贝,这意味着在循环中对 `i` 的修改会影响到数组 `arr` 中对应位置的值。arr则是需要遍历的数组。一、为啥要转C++:之前只学过C语言,然后为了蓝桥杯苦哈哈敲了C好久,偶然听了别人的意见去看了一下C++后发现简直太香了——C++不像C要把底层逻辑自己敲出来,而是可以直接调用STL函数库(比如排序,C语言可能要敲个几十行代码C++直接用调用sort函数就可以了),而且C++完全兼容C语言,里面的语法全部可以用C替换。 阅读详情

相关推荐

本地AI语音生成与配音工作台Pandrator:从TTS到RVC的完整实践指南

语音合成(TTS)技术通过深度学习模型将文本转换为自然语音,其核心原理涉及声学建模与波形生成。这项技术不仅提升了人机交互体验,更在内容创作领域展现出巨大价值,广泛应用于有声书制作、视频配音、虚拟助手等场景。本文聚焦于一个集成了XTTS-v2、RVC等先进模型的本地化AI语音工作台——Pandrator,它通过模块化架构将语音合成、声音克隆、音频转录与翻译等流程无缝整合,为用户提供了一个图形化、可定制的完整解决方案。文章深入解析了其基于TTS与RVC(Retrieval-based Voice Convers

weixin_42676876的博客 340

Java中的21种锁

本篇主要内容如下: 本篇主要内容 本篇文章已收纳到我的Java在线文档、 Github 我的SpringCloud实战项目持续更新中 帮你总结好的锁: 序号锁名称应用1乐观锁CAS2悲观锁synchronized、vector、hashtable3自旋锁CAS4可重入锁synchronized、Reentrantlock、Lock5读写锁ReentrantReadWriteLock,CopyOnWriteArrayList、CopyOnWriteArraySet6公平锁Reentrant.

新技术革命 1223

TensorFlow_PyTorch实战:构建AI人工智能回归模型

回归分析是机器学习的核心任务之一,用于预测连续型目标变量(如房价、股票价格、用户留存时间等)。基础线性回归模型的数学原理与代码实现多项式回归模型的过拟合处理与正则化技巧自定义数据集加载与数据预处理流程动态图(PyTorch)与静态图(TensorFlow)的编程范式对比模型评估指标与可视化分析方法核心概念:对比两大框架的架构设计,解析回归模型核心组件数学原理:推导线性回归的假设函数、损失函数及优化算法算法实现:提供TensorFlow和PyTorch的完整代码示例项目实战。

AI天才研究院 1430

JUC之读写锁/独占锁(写锁)和共享锁(读锁)

乐观锁 悲观锁: 写锁的死锁:

weixin_38568503的博客 538

CELF(Cost-Effective Lazy Forward selection)具有成本效益的惰性前向选择算法

CELF(Cost-Effective Lazy Forward selection)算法解析      引言:在社交网络影响力最大化问题的求解过程中,我们往往需要去选择一些目标种子结点作为信息初始传播的源头。贪婪算法在传播效果上的解决可以达到影响的最大化,但是在时间复杂度上面显得确十分糟糕。为此CELF算法应势而生,CELF算法利用了函数次模性的特点,在第一轮选择种子结点时,计算网络中所有节点的边际收益,但将在之后的过程中,不再做网络节点边际收益的重复计算,这相对于传统的贪婪算法,将在时间上得到非常明显的

hahaxq的博客 2477

GD32F470实战:如何用EXMC+SDRAM搞定LVGL大内存需求(附完整代码)

本文详细介绍了如何在GD32F470微控制器上通过EXMC接口驱动外部SDRAM,以满足LVGL图形库的大内存需求。内容涵盖硬件连接、EXMC时序配置、轻量级内存管理器实现,以及将LVGL帧缓冲和资源无缝集成到SDRAM的实战方法,并提供了完整的代码示例和调试技巧,帮助开发者构建稳定可靠的嵌入式GUI系统。

k9l0m1的博客 442

JUC包下各种锁使用详解

JUC包下各种锁使用详解

weixin_42672802的博客 424

从ADRV9002到ADRV9003:手把手教你移植FPGA驱动,避开那些官方没说的坑

本文详细介绍了从ADRV9002到ADRV9003的FPGA驱动移植实战指南,重点解析了两者在硬件架构上的关键差异,如通道配置和DPD功能的移除。通过提供完整的移植步骤、调试技巧和性能优化建议,帮助工程师避开官方文档未提及的常见陷阱,实现高效驱动开发。

weixin_28738397的博客 177

JUC之五:AQS共享锁的获取和释放(Semaphore代码解析)

文章目录共享锁与独占锁的区别Semaphore内部类共享锁的获取setHeadAndPropagate执行doReleaseShared的条件共享锁的释放同时执行doReleaseShared总结 共享锁与独占锁的区别 共享锁在同一时刻多个线程占有锁,独占锁同一时刻只能有一个线程占有锁,并把线程放在exclusiveOwnerThread成员上。 共享锁与独占锁都需要被唤醒。 共享锁唤醒线程有两种方式:  1、在唤醒线程的同时,该线程也会尝试唤醒后面的线程(在setHeadAndPropagate方法

zhengguofeng0328的博客 828

jetson orin nano 使用cuPCL

jetson开发板上使用pcl时,正常使用的是cpu,拖慢了整体的效率。cuPCL有一些库用于使用CUDA处理点云。

weixin_42256401的博客 1020

DeepFashion 服装识别:基于 YOLOv10 的深度学习实现与 UI 界面开发

随着深度学习的发展,目标检测算法在服装识别任务中表现出色,特别是 YOLO(You Only Look Once)系列模型。服装识别(Fashion Recognition)是计算机视觉领域的重要任务,广泛应用于。已提供,可用于服装分类、款式识别、虚拟试衣等应用。训练服装识别模型,并开发。

YOLO 803

多线程-JUC学习-锁-11.共享锁-Semaphore

1、Semaphore简介 Semaphore是一个计数信号量,它的本质是一个"共享锁"。 信号量维护了一个信号量许可集。线程可以通过调用acquire()来获取信号量的许可;当信号量中有可用的许可时,线程能获取该许可;否则线程必须等待,直到有可用的许可为止。 线程可以通过release()来释放它所持有的信号量许可。 Semaphore的函数列表 // 创建具有给定的许可数和非公平的公...

zongx的博客 281

【ComfyUI】VideoRefusion 动态替换视频背景

本文介绍了一个基于ComfyUI的视频背景替换工作流,通过WanVAE和WanTextEncoder核心模型实现人物与背景的智能分离与替换。工作流包含9个关键流程阶段,涉及视频采样、图像增强等节点操作,可生成风格统一、动作自然的视频效果。该技术适用于虚拟人物创作、短视频特效、产品广告等场景,支持个性化定制开发。相关资源可参考文末提供的ComfyUI教程和AIGC工具平台开发指南。(149字)

Mr数据杨 2191

AQS简单介绍与使用

AQS,全称是 AbstractQueuedSynchronizer,中文译为抽象队列式同步器。这个抽象类对于JUC并发包非常重要,JUC包中的ReentrantLock,,Semaphore,ReentrantReadWriteLock,CountDownLatch 等等几乎所有的类都是基于AQS实现的。 AQS 中有两个重要的东西,一个等待队列,还有一个STATE标志,并且通过CAS来改变它的...

charming的专栏 2万+

WINCC7.3破解文件

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

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

深入解析Java多线程与并发编程(五)(JUC显示锁、AQS抽象同步器以及JUC高并发容器)

本文介绍了JUC显式锁、AQS抽象同步器以及JUC高并发容器的基本概念。JUC显式锁是一种灵活的Java实现锁,支持多种锁操作,如可轮询、定时、可中断等。显式锁的核心接口是Lock,其主要实现类为ReentrantLock,具有可重入、独占等特性。显式锁可分为可重入锁、不可重入锁、悲观锁、乐观锁、公平锁、非公平锁、可中断锁、不可中断锁、共享锁和独占锁等类型。悲观锁适用于写多读少场景,而乐观锁适用于读多写少场景。公平锁保障线程按顺序获取锁,非公平锁则不保证。可中断锁允许在抢占过程中中断,而不可中断锁则不允许。

wxchyy的博客 1416

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

【JUC源码】JUC核心:AQS(三)同步队列源码分析(共享锁)

AQS 系列: 【JUC源码】JUC核心:AQS(一)底层结构分析 【JUC源码】JUC核心:AQS(二)同步队列源码分析(独占锁) 【JUC源码】JUC核心:AQS(三)同步队列源码分析(共享锁) 【JUC源码】JUC核心:AQS(四)条件队列源码分析 【JUC源码】JUC核心:关于AQS的几个问题 1.共享-加锁 共享锁和排他锁最大的不同在于:对于同一个共享资源,排他锁只能让一个线程获得 acquireShared() 共享模式下,尝试获得锁 // 共享锁可以让多个线程获得,arg 可以被子类当.

A minor 585

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

JUC-AQS原理篇

AQS全称是AbstractQueuedSynchronizer,这个抽象类是java并发包java.util.concurrent.locks(JUC)中的核心,它是JUC包下面多个组件的底层实现。比如CountDownLatch,Semaphore,CyclicBarrier,ReentrantLock,ReentrantReadWriteLock,ThreadPoolExecutor等的底层实现都用到了AQS。简单来讲,AQS是一个抽象类,这些组件的共性功能,它实现了,差异化的功能,它提供接口,由具体

zqj1172102457的博客 655

高并发之JUC——AQS源码深度分析(一)

不要只满足于目前的安逸,傻傻的在工作中写CRUD了。因为在目前疫情面前,企业依然朝不保夕。我们不能温水煮青蛙,只有时刻保持一颗学习的心,拥有硬核能力,时刻心如止水,才能立于不败之地。 这是高并发JUC的系列的第一篇。AbstractQueuedSynchronizer简称AQS,它是JUC工具类的基石,JUC包下的类都直接或间接的继承了AbstractQueuedSynchronizer,而JUC是jdk自带的实现高并发的辅助工具。所以我们首先分析AQS源码,才能更好的学习JUC并发包中的其他工具类。 .

qq_20878967的博客 971

死磕JUC之AQS源码,一篇就够

AQS(抽象队列同步器)前言简单了解AQS的应用同步组件JUC中的锁AQS的结构Node节点AQS 队列结构图独占锁acquire(获取锁)1、tryAcquire(尝试获取锁)2、addWaiter(添加等待节点)3、acquireQueued(排队获取锁)获取独占锁的流程图总结release(释放锁)1、tryRelease(尝试释放锁)2、unparkSuccessor(唤醒后继节点)共享锁acquireShared(获取同步状态)1、tryAcquireShared(尝试获取锁)2、doAcquir

qq_41743796的博客 765

JAVA并发编程AQS原理剖析

很多小朋友面试时候,都会被面试官问:说一下AQS原理。面对并发编程基础和面试经验,拉丁解牛专栏采用通俗简洁无废话无八股文方式剖析原理和源码,让天下没有难啃的技术。

拉丁解牛技术专栏 1475

JUC源码系列-AQS共享锁的获取与释放

共享锁与独占锁的最大不同,是共享锁可以同时被多个线程持有,虽然AQS里面没有成员用来保存持有共享锁的线程们。由于共享锁在获取锁和释放锁时,都需要唤醒head后继,所以将其逻辑抽取成一个的逻辑了。

Quasimodo24的博客 544

AQS 共享锁模式

前沿 上一篇文章已经向大家讲解了AQS的数据结构,以及独占锁的源码详解,本篇文章接着介绍AQS的共享锁模式,学习并发编程一定要把AQS搞懂,因为JUC包中的很多类都是由AQS实现的。 AQS共享模式acquireShared执行流程 多个线程通过调用tryAcquireShared方法获取共享资源,返回值大于等于0则获取资源成功,返回值小于0则获取失败。 当前线程获取共享资源失败后,通过调...

qqinternet的博客 374

JUC之AQS解读

AQS简介 AQS(AbstractQueuedSynchronizer)是一个模板类,其提供一个先进先出(FIFO)的等待队列,旨在为大多数依赖单个原子int值表示状态的同步器提供有用的基础。 AQS类支持默认的排他锁和共享锁之一或两者。在排他锁模式下获取时,其他线程尝试获取是不会成功的,共享模式由多个线程获取可能会(但不一定)成功。AQS类不会“理解”这些区别,只是锁意义上说,当成功获取共享模式时,下一个等待线程(如果存在)也必须确定它是否也能够获取。在不同模式下等待的线程共享相同的FIFO队列。 如果

相逢一笑 779

JUC——AQS

​​AQS(AbstractQueuedSynchronizer)是 Java 并发包中用于构建锁和同步器的核心框架,它通过一个 volatile 状态变量和 FIFO 等待队列,提供了线程同步的底层支持,开发者可通过继承 AQS 并实现 tryAcquire / tryRelease 等方法,轻松实现自定义的同步组件。​。

qq_57019146的博客 1068

AQS深入理解系列(三)共享锁的获取与释放

独占锁是线程独占的,同一时刻只有一个线程能拥有独占锁,AQS里将这个线程放置到exclusiveOwnerThread成员上去。 共享锁是线程共享的,同一时刻能有多个线程拥有共享锁,但AQS里并没有用来存储获得共享锁的多个线程的成员。 如果一个线程刚获取了共享锁,那么在其之后等待的线程也很有可能能够获取到锁。但独占锁不会这样做,因为锁是独占的。 当然,如果一个线程刚释放了锁,不管是独占锁还是共享锁,都需要唤醒在后面等待的线程。

anlian523的博客 3293

AQS系列文章 | 并发编程基石:为什么需要AQS?

全称:AbstractQueuedSynchronizer(抽象队列同步器)身份包中的抽象类职责:为构建锁和同步器提供基础设施(如线程排队、状态管理)AQS就像乐高积木:你不需要从零造轮子,只需组合它提供的基础模块(状态管理、线程排队),就能搭建出ReentrantLock、Semaphore等强大的同步工具。下一篇预告《AQS核心原理:状态与队列机制》——我们将拆解AQS内部的神秘“计数器”和“排队区”,用动画演示线程如何有序等待!

ibigboy 827
上一篇: JUC之线程池
下一篇: SpringMVC-web项目和HttpInvoker
define_us
博客等级 码龄14年 157粉丝 531原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值