秋招突击——7/19——队列同步器AQS学习

news2024/9/22 22:34:24

文章目录

    • 引言
    • 基础知识
      • 简介
      • AQS接口和示例
        • 第一类:访问和修改同步状态的方法
        • 第二类,5个重写的方法
        • 第三类,9个模板方法
      • 队列同步器实现原理
        • 同步队列
        • 独占式同步获取和释放
        • 共享式同步获取和释放
        • 独占式同步获取和释放
    • 相关面试题
      • 怎么理解Lock和AQS的关系
      • 什么是AQS
      • AQS是怎么实现同步管理的?底层数据结构?
      • AQS有哪些核心方法
    • 总结

引言

  • 学了锁,学了多线程编程,学了线程池,发现很多都提到了AQS,现在来补一下,也是填一下以前留下的坑。
    • 坑位在这里插入图片描述
  • 还是跟以前一样,先过一遍基础知识,然后再过一遍相关的面试题

基础知识

简介

  • 队列同步器AbstractQueuedSynchronizer
    • 构建锁和其他同步组建的基础框架

      • 使用int变量表示同步状态,通过内置的队列完成线程排队工作,是实现大部分同步需求的基础
      • 仅仅定义若干同步状态的获取和释放方法,来实现线程同步,没有实现任何接口
      • 支持独占式和共享式获取同步状态
    • 使用方式继承

      • 子类通过继承并实现方法管理同步状态,使用getState(),setState()和compareAndSetState来修改状态

AQS接口和示例

  • AQS的实现采用的是模板模式,使用他对外提供的三类方法来实现一个同步组件。

    • 这里又不知道模板模式了,得去好好学一下了,学习链接
  • 三类方法分别如下

    • 第一类:同步器提供的用于访问和修改同步状态的三个方法
    • 第二类:继承AQS并重写的5个方法
    • 第三类:9个模板方法,用来组合AQS形成自定义的同步组件
      这里给一个自定义的锁的样例mutex
  • 第一步先在同步器中创建一个内部类继承并实现AQS,重写对应5个方法
    在这里插入图片描述

  • 调用9个模板方法,组合对应同步器的逻辑

在这里插入图片描述

第一类:访问和修改同步状态的方法

重写同步器指定的5个方法时,需要使用同步器提供的如下的三个方法来访问和修改同步状态

  • getState:获取当前同步状态
  • setState(int newState):设置当前同步状态
  • CompareAndSetState(int expect,int update):使用CAS设置当前状态,保证状态设置的原子性
第二类,5个重写的方法
  • isHeldExclusively
    • 判定该线程是否正在独享资源,只有用到condition的时候,才需要实现它
  • tryAcquire(int)
    • 独占的方式,尝试获取资源,成功就返回true,失败就返回false
  • tryRelease(int)
    • 独占的方式,尝试释放资源,成功就返回true,失败就返回false
  • tryAcquireShared
    • 共享方式,尝试获取资源
    • 负数表示失败,0表示成功但是没有可用资源剩余,正数表示成功并且有剩余资源
  • tryReleaseShared
    • 共享方式,尝试释放资源
    • 成功返回true,失败返回false
第三类,9个模板方法

模板方法主要分成三类

  • 独占式获取和释放同步状态
  • 共享式获取和释放同步状态
  • 查询同步队列中的等待线程

第一类,独占式获取和释放同步状态

  • void acquire

    • 独占式获取同步状态,获取成功由该方法返回,否则进入同步队列等待
    • 调用重写的tryAcquire方法
  • void acquireInterruptibly

    • 同上,但是支持响应中断
    • 当前线程未获取到同步状态,而进入同步队列中,如果线程被中断,该方法抛出InterruptedException
  • void tryAcquireNanos

    • 同上,但是支持响应中断,而且增加了超时机制
    • 当前线程在超时时间内没有获取到同步状态,就会返回false,否则返回true
  • bool release

    • 独占式释放同步状态
    • 释放同步状态后,将同步队列中的第一个节点唤醒

第二类,共享式获取和释放同步状态

  • void acquireShared

    • 共享式获取同步状态,获取成功由该方法返回,否则进入同步队列等待
    • 与独占式的区别是同一时刻,有多个线程获取同步状态
  • void acquireSharedInterruptibly

    • 同上,但是支持响应中断
    • 当前线程未获取到同步状态,而进入同步队列中,如果线程被中断,该方法抛出InterruptedException
  • void tryAcquireSharedNanos

    • 同上,但是支持响应中断,而且增加了超时机制
    • 当前线程在超时时间内没有获取到同步状态,就会返回false,否则返回true
  • bool releaseShared

    • 共享式释放同步状态
    • 释放同步状态后,将同步队列中的第一个节点唤醒

第三类、获取同步队列中的线程

  • collection getQueueThread
    • 获取等待在同步队列上的线程的集合

这里给一个自定义的锁的样例mutex

  • 第一步先在同步器中创建一个内部类继承并实现AQS,重写对应5个方法
    在这里插入图片描述
  • 调用9个模板方法,组合对应同步器的逻辑

在这里插入图片描述
具体代码

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public class Mutex implements Lock {

    // 定义一个静态内部类,用来继承AQS
    private static class Sync extends AbstractQueuedSynchronizer{
        // 是否处于占用状态
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        // 当状态为0的时候获取锁
        @Override
        protected boolean tryAcquire(int arg) {
            if(compareAndSetState(0,1)){
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        // 释放锁,将状态设置为0
        @Override
        protected boolean tryRelease(int arg) {
            if(getState() == 0) throw new IllegalMonitorStateException();
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        // 返回一个Condition,每个condition都包含了一个condition队列
        Condition newCondition(){
            return new ConditionObject();
        }
    }

    // 将操作代理到Sync上
    private final Sync sync = new Sync();

    @Override
    public void lock() {
        sync.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1,unit.toNanos(time));
    }

    @Override
    public void unlock() {
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }
}

总结
基本步骤如下

  • 继承Lock接口
  • 定义一个内部静态类AQS的子类,重写5个重写方法,调用3个状态修改函数实现
  • 使用9个模板方法实现Lock规定的接口方法
    • 将操作代理到AQS子类Sync上,利用Sync的14种方法来实现Lock

队列同步器实现原理

同步队列


队列节点

  • 节点Node是构成同步队列的基础,获取同步状态失败的线程将会被包装成一个节点,加入到同步队列的尾部。
  • 属性
    • waitStatus等待状态
      • cancelled表示线程超时或者中断,从队列中取消等待
      • signal表示后继节点处于等待状态,当前节点释放同步状态会通知后继节点
      • condition表示节点在等待队列中, 节点等待在Condition对象为锁的等待队列上,当其他线程对Condition调用signal方法时,该节点将等待队列转移到同步队列,加入到同步状态的获取中。
      • propagate表示下一个共享式同步状态将会无条件传播下去
    • prev和next:表示同步队列中的前驱节点和后继节点
    • nextWaiter:等待队列中的后继节点
独占式同步获取和释放
  • 获取同步状态时,主要是通过维护一个同步队列实现
    • 获取状态失败的线程会加入到同步队列中,自旋并尝试获取同步状态
    • 释放同步状态,同步器调用tryRelease方法,释放同步状态,唤醒后继节点
共享式同步获取和释放
  • 共享式同步获取实现

    • 调用tryAcquireShared方法,根据返回的int值判定,大于等于零表示获取成功,这个值表示剩余的资源数。
  • 调用releaseShared方法释放同步状态

独占式同步获取和释放
  • 使用理解
    • 强于Synchronized关键字,能够实现在指定时间内获取同步状态,调用同步器地doAcquireNanos实现
    • 支持中断
  • 设置时间过短
    • 如果设置时间过短,会进入快速自旋过程

相关面试题

怎么理解Lock和AQS的关系

  • Lock
    • 面向锁的使用者,定义了使用者和锁的交互接口,隐藏了实现细节
  • AQS
    • 面向锁的开发者,简化了锁的实现,屏蔽了同步状态的管理,线程的排队等操作
  • 二者很好地隔离了使用者和实现者所需要关注的领域

什么是AQS

  • 队列同步器AQS(AbstractQueuedSynchronizer)
    • 用来构建锁和实现其他同步组件的基础框架
    • 使用int成员变量state表示同步状态
    • 通过内置的FIFO队列完成想要获取资源的线程的排队工作
  • 使用方式
    • 通过继承,子类继承同步器并实现抽象方法来管理同步状态。
      • 子类被推荐为自定义同步组建的静态内部类,同步器自身没有实现任何同步接口,仅仅是定义了若干同步状态获取和释放的方法来自定义同步组件
    • 提供3个获取和修改同步状态的安全方法,getstate,setstate,compareAndSetState
    • 同步器同时支持独占式获取同步状态和共享式获取同步状态
    • 典型的应用
      • ReentrantLock、读写锁ReenReadWriteLock等

AQS是怎么实现同步管理的?底层数据结构?

  • 实现方式
    • 使用双向链表和使用volatile修饰的int型变量state
      • state
        • 0 没有线程占用同步资源
        • 大于0 有线程占用同步资源
        • 大于1 同步资源已经被占用了很多次
      • 双向链表,基于FIFO的同步队列
        • 通过将等待线程加入同步队列,实现线程获取同步状态失败的管理
        • 释放同步状态的时候,从同步队列中唤醒等待线程,实现同步机制。
  • 典型应用
    • 独占式:只有一个线程可以占用同步资源
      • reentrantLock
    • 共享式:多个线程占用共享资源
      • CountDownLatch
  • 上述两种方式在底层都是AQS实现的,且实现方式基本相同,区别在于获取和释放同步状态的方式不同。

AQS有哪些核心方法

  • 一共有三类方法
    • 第一类:3个访问和修改同步状态的方法
    • 第二类:5个需要重写的方法,调用上述三个方法重写
    • 第三类:9个模板方法,由外界具体调用实现不同同步组件
  • 三类方法关系:
    • 实现一个同步组件时,使用者继承AbstractQueuedSynchronizer并重写5个指定的方法(第二类)。重写同步器指定的方法时,需要使用同步器提供的3个方法来访问或修改同步状态(第一类)
    • 最后将AQS组合在自定义同步组件的实现中,并调用其9个模板方法(第三类)和 5个重写过的方法来实现,另外模板方法会调用使用者重写的方法。

总结

  • 我觉这些框架的东西不是很好理解,过分偏向于底层了,然后理解起来有比较费劲,背起来也比较难,问的也比较少,但是总是在很多地方有体现,这里还是得学习一下!
  • 这个过了,多线程编程算是过了,还有一些并发容器(ConcurrentHashMap和CopyOnWriteList)以及并发工具类没有实现,这里还是抽空再看吧!感觉问到的比较少!
  • 招工作真的不容易呀,学的我想死,每天的学习任务都好重!还是害怕找不到好工作!白读了研究生!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1938576.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何解决热插拔时的电压过冲

摘要 热插拔是指将上电电压源连接到电子器件的输入电源或电池连接器。热插拔产生的电压瞬态尖峰会损坏器件内部的集成电路。该文解释了此类电压瞬变的根本原因,并提供了防止这些瞬变损坏电子产品中的集成电路(IC) 的可能设计。 1 引言 当将高于 5V 的 USB 适配器…

达梦数据库的系统视图v$dmwatcher

达梦数据库的系统视图v$dmwatcher 查询当前登录实例所对应的守护进程信息,注意一个守护进程可以同时守护多个组的实例,因此查询结果中部分字段(N_GROUP、SWITCH_COUNT)为守护进程的全局信息,并不是当前登录实例自身的…

BUUCTF - Web - 1

文章目录 1. [极客大挑战 2019]EasySQL 1【SQL注入-万能密码】2. [极客大挑战 2019]Havefun 1【前端代码审计-注释泄漏】3. [HCTF 2018]WarmUp 1【PHP代码审计】4. [ACTF2020 新生赛]Include 1【PHP伪协议】5. [ACTF2020 新生赛]Exec 1【命令注入-基础】6. [GXYCTF2019]Ping Pi…

张量网络碎碎念:CGC

在本系列 上一篇文章 中,我介绍了张量网络的一些基础概念。其中很大一部分来自 github 上一个教程。事实上,该教程的大部分内容来自 e3nn 官网。 除了上篇文章介绍的一些可视化技巧,官网还提供了其他一些可视化模块。使用这些功能能使我们更深…

windows USB 设备驱动开发-开发Type C接口的驱动程序(三)

编写 USB Type C 端口控制器驱动程序 如果 USB Type-C 硬件实现 USB Type-C 或电源传送 (PD) 物理层,但未实现供电所需的状态机,则需要编写 USB Type-C 端口控制器驱动程序。 在 Windows 10 版本 1703 中,USB Type-C 体系结构已得到改进&am…

云监控(华为) | 实训学习day5(10)

Gaussdb安装和连接idea GaussDB的安装 首先关闭防火墙 systemctl disable firewalld.service 永久关闭防火墙(发生在下次启动) systemctl stop firewalld.service 关闭本次防火墙 查看防火墙状态systemctl status firewalld.service 查询的状态是Dead表…

【算法】百钱买百鸡问题算法详解及多语言实现

问题描述 百钱买百鸡问题是一个经典的数学问题,题目要求用100文钱买100只鸡,公鸡5文钱一只,母鸡3文钱一只,小鸡3只一文钱,问公鸡、母鸡、小鸡各买多少只? 目录 问题描述​编辑 解决方案 Python实现 Ja…

选择Maya进行3D动画制作与渲染的理由

如果你对3D动画充满热情并追求成为专业3D动画师的梦想,你一定听说过Maya——近年来3D动画的行业标准。Maya被3D艺术家广泛使用,你是否想知道为什么Maya总是他们的首选?下面一起来了解下。 一、什么是Maya? 由Autodesk开发的Maya是…

wxid转微信号

7.21由于微信的再一次调整,能够转出微信号的接口已经和谐,根据客户要求琢磨了几个小时 发现新的接口也是可以批量转换的

springcolud学习06Hystrix

Hystrix Hystrix是Netflix开发的一个用于处理分布式系统中延迟和容错问题的库。它主要用于防止分布式系统中的雪崩效应,通过在服务之间添加延迟容错和故障处理机制来增强系统的弹性。 服务熔断 类似于电路中的断路器,当失败率超过阈值时,Hystrix 可以自动地开启断路器,停…

c++习题12-开关灯

目录 一,题目 二,思路 三,代码 一,题目 用例输入 1 10 10 用例输出 1 1,4,9 二,思路 创建可以存放路灯亮灭情况的数组,路灯的编号从1开始,因此在使用for循环去初始化数组时&#xff…

初识模板【C++】

P. S.:以下代码均在VS2022环境下测试,不代表所有编译器均可通过。 P. S.:测试代码均未展示头文件stdio.h的声明,使用时请自行添加。 博主主页:LiUEEEEE                        …

编写小程序用什么软件

编写小程序时,可以使用多种软件或工具,这些工具通常提供了丰富的开发功能和组件,方便开发者进行小程序的创建、开发和调试。以下是一些常用的编写小程序的软件和工具: DIY官网可视化工具 可视化拖拽开发神器|无须编程 零代码基础…

HashMap原理详解,HashMap源码解析

HashMap是一个数组链表和红黑树的结合体 HashMap的第一层表现是数组,HashMap默认创建一个长度为十六的数组来储存数据,但不同的是,它并非是先放在第0个索引,然后第一个索引那么放置,而是通过key获取对应的32位hash值&a…

OAuth2.0 or Spring Session or 单点登录流程

1.社交登录 2.微博社交登录 第三方登录 1.登录微博 2.点击网站接入 3.填写完信息,到这里,写入成功回调 和 失败回调 是重定向,所以可以写本地的地址 3.认证 分布式Session spring-session 域名不一样 发的 jSessionId 就不同&#xff0c…

uniapp,vue3上传图片组件封装

首先创建一个 components 文件在里面进行组件的创建 下面是 vip组件的封装 也就是图片上传组件 只是我的命名是随便起的 <template><!--图片 --><view class"up-page"><!--图片--><view class"show-box" v-for"(item,ind…

STM32的串口(RS485)数据收发

一、前言 我们的单片机串口一般常用RS232、RS485、TTL这几种通讯方式&#xff0c;日常调试可能RS232、TTL比较多&#xff0c;真正和其它厂家数据交互的时候&#xff0c;还是RS485用的比较多&#xff0c;因为它是差分信号等电气属性&#xff0c;所以比较稳定&#xff0c;传输距…

Matlab演示三维坐标系旋转

function showTwo3DCoordinateSystemsWithAngleDifference() clear all close all % 第一个三维坐标系 origin1 [0 0 0]; x_axis1 [1 0 0]; y_axis1 [0 1 0]; z_axis1 [0 0 1];% 绕 x 轴旋转 30 度的旋转矩阵 theta_x 30 * pi / 180; rotation_matrix_x [1 0 0; 0 cos(th…

SpringBoot使用本地缓存——Caffeine

SpringBoot使用本地缓存——Caffeine 缓存&#xff0c;想必大家都用过&#xff0c;将常用的数据存储在缓存上能在一定程度上提升数据存取的速度。这正是局部性原理的应用。之前用的缓存大多是分布式的&#xff0c;比如Redis。使用Redis作为缓存虽然是大多数系统的选择&#xf…

基于重要抽样的主动学习不平衡分类方法ALIS

这篇论文讨论了数据分布不平衡对分类器性能造成的影响,并提出了一种新的有效解决方案 - 主动学习框架ALIS。 1、数据分布不平衡会影响分类器的学习性能。现有的方法主要集中在过采样少数类或欠采样多数类,但往往只采用单一的采样技术,无法有效解决严重的类别不平衡问题。 2、论…