深入理解AQS:并发编程中的利器及其在业务场景中的应用

1. 什么是AQS(AbstractQueuedSynchronizer)?

AQS,全称为AbstractQueuedSynchronizer,是Java并发包中核心的基础框架,用于构建锁和同步器。它是java.util.concurrent.locks包中的基础组件,为多个同步类提供了共享的功能,比如ReentrantLockCountDownLatchSemaphore等。

AQS的主要作用是:

  • 管理锁的状态:通过一个整型状态state变量来表示锁的状态,如是否获取锁,当前锁的持有线程是谁。
  • FIFO等待队列:当线程争抢资源失败时,AQS会将其放入一个FIFO(先进先出)队列中进行管理。

2. AQS的工作原理

AQS通过一个整数变量state来表示锁的状态:

  • state == 0时,表示锁是空闲状态;
  • state > 0时,表示锁已被线程占用。

AQS通过两种模式来实现锁机制:

  • 独占模式(Exclusive):只有一个线程能获取锁,如ReentrantLock
  • 共享模式(Shared):多个线程可以同时获取锁,如CountDownLatch

3. 关键机制

  • 获取锁的流程:尝试获取资源(tryAcquire),如果成功则直接执行;否则,进入等待队列。
  • 释放锁的流程:通过tryRelease释放资源,唤醒队列中的等待线程。
  • 等待队列:如果获取锁失败,线程会被放入等待队列,等待其他线程释放锁资源。

4. Java模拟代码:自定义锁基于AQS

为了深入理解AQS的工作原理,以下是一个基于AQS的简易独占锁的实现:

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

public class CustomLock {
    // 内部类继承AQS,实现独占锁逻辑
    private static class Sync extends AbstractQueuedSynchronizer {
        // 尝试获取锁(独占模式)
        @Override
        protected boolean tryAcquire(int acquires) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread()); // 设置持有锁的线程
                return true;
            }
            return false;
        }

        // 尝试释放锁
        @Override
        protected boolean tryRelease(int releases) {
            if (getState() == 0) {
                throw new IllegalMonitorStateException();
            }
            setExclusiveOwnerThread(null); // 清空持有锁的线程
            setState(0); // 设置状态为0,表示锁已释放
            return true;
        }

        // 是否被占用
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }
    }

    private final Sync sync = new Sync();

    // 获取锁
    public void lock() {
        sync.acquire(1);
    }

    // 释放锁
    public void unlock() {
        sync.release(1);
    }

    public boolean isLocked() {
        return sync.isHeldExclusively();
    }
}

public class CustomLockTest {
    public static void main(String[] args) {
        CustomLock lock = new CustomLock();

        // 创建多个线程模拟锁的竞争
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + " is trying to acquire the lock.");
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " has acquired the lock.");
                    Thread.sleep(2000); // 模拟业务处理
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    System.out.println(Thread.currentThread().getName() + " is releasing the lock.");
                    lock.unlock();
                }
            }).start();
        }
    }
}

5. 代码详细解释

在这里插入图片描述

  1. Sync类继承自AbstractQueuedSynchronizer

    • tryAcquire:尝试获取锁,通过CAS操作(compareAndSetState(0, 1))来判断当前锁是否空闲。如果成功获取锁,则设置当前线程为锁的持有者。
    • tryRelease:释放锁时,检查锁状态并将其设置为0,同时清除持有锁的线程信息。
    • isHeldExclusively:用于检查当前线程是否持有锁。
  2. CustomLock

    • lock():调用AQS的acquire方法尝试获取锁。
    • unlock():调用AQS的release方法释放锁。
  3. CustomLockTest

    • 创建多个线程,模拟锁的竞争。每个线程尝试获取锁,成功后模拟业务处理,并在完成后释放锁。

6. 运行结果

运行后,多个线程尝试获取锁,由于我们实现的是独占锁,只有一个线程可以持有锁,其他线程会进入等待状态,直到锁被释放。

示例输出(简化):

Thread-0 is trying to acquire the lock.
Thread-0 has acquired the lock.
Thread-1 is trying to acquire the lock.
Thread-2 is trying to acquire the lock.
Thread-0 is releasing the lock.
Thread-1 has acquired the lock.
Thread-1 is releasing the lock.
...

从输出中可以看出,多个线程争抢锁,只有一个线程可以获取,其他线程会等待。

7. 使用场景及问题解决

使用场景:
  1. 锁的实现:AQS是实现Java锁机制的核心,可以用它实现自定义的同步器,如互斥锁、读写锁等。
  2. 信号量:AQS的共享模式可以用来实现Semaphore,允许多个线程同时获取锁。
  3. 倒计时器(CountDownLatch):通过AQS实现线程同步,多个线程等待一个事件发生。
解决的问题:
  • 线程安全的资源访问:通过AQS可以确保在多线程环境下,多个线程对共享资源的有序访问,避免竞争条件和数据不一致问题。
  • 灵活的同步控制:通过AQS的独占和共享模式,可以实现灵活的同步控制策略,适应不同的业务需求。

8. 借用AQS思想的业务场景

场景示例:分布式任务调度器的锁控制

在分布式系统中,多个节点可能会同时尝试执行某个任务,比如调度定时任务或处理某些业务逻辑。为了防止多个节点同时执行同一个任务,我们可以借助AQS实现分布式任务调度锁。

使用AQS的独占模式,可以保证只有一个节点能够获取锁,并执行任务。其他节点会被阻塞,直到锁被释放。

public class DistributedTaskScheduler {
    private static final CustomLock lock = new CustomLock();

    public static void main(String[] args) {
        // 多个节点模拟任务调度
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                try {
                    if (lock.isLocked()) {
                        System.out.println(Thread.currentThread().getName() + ": Task already in progress by another node.");
                    } else {
                        lock.lock();
                        System.out.println(Thread.currentThread().getName() + ": Acquired lock and started task.");
                        Thread.sleep(3000); // 模拟任务执行
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                    System.out.println(Thread.currentThread().getName() + ": Released lock and finished task.");
                }
            }).start();
        }
    }
}
解释:
  • 在分布式任务调度中,多个节点会尝试获取锁并执行任务,使用AQS确保只有一个节点能成功获取锁,防止任务重复执行。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

屏幕画面卡住不动声音正常怎么办?电脑屏幕卡住不动解决方法

在数字时代&#xff0c;电脑作为我们日常生活与工作中不可或缺的伙伴&#xff0c;偶尔也会遇到一些小状况。其中&#xff0c;“屏幕画面卡住不动&#xff0c;但是声音依然正常”的情况就是一种常见的问题。本文将探讨这一现象的原因&#xff0c;并提供几种可能的解决方案&#…

FSCapture 9.3 | 全能截图与录屏解决方案。

FastStone Capture 是一款轻量级但功能全面的屏幕捕捉工具&#xff0c;能够轻松捕获并标注屏幕上的一切内容&#xff0c;包括窗口、对象、菜单、全屏、矩形/自由区域以及滚动窗口或网页。此外&#xff0c;它还支持录制屏幕活动、声音和网络摄像头&#xff0c;并将这些内容保存为…

[复现]比较6种股市趋势识别方

作者: Filippos Tzimopoulos 翻译整理&#xff1a;进击的小学生 文章名称: I compared 6 methods to identify the trend of the stock market. These are the results! code 与 datas &#xff0c;请转至获取&#xff01; 背景说明 通过识别市场方向&#xff0c;交易者可…

webAPI中的排他思想、自定义属性操作、节点操作(配大量案例练习)

一、排他操作 1.排他思想 如果有同一组元素&#xff0c;我们想要某一个元素实现某种样式&#xff0c;需要用到循环的排他思想算法&#xff1a; 1.所有的元素全部清除样式 2.给当前的元素设置样式 注意顺序能不能颠倒&#xff0c;首先清除全部样式&#xff0c;再设置自己当前的…

dyna批处理代码,无需蹲守,自行连续计算

用此代码即可 上面一行是模型位置 下面一行是DYNA模拟器位置 第三个框框是K文件名称 上述三者改成自己的 然后复制修改即可 复制几个就几个进行批处理

深入理解伪元素与伪类元素

在“探秘盒子浮动&#xff0c;破解高度塌陷与文字环绕难题&#xff0c;清除浮动成关键&#xff01;”中&#xff0c;我们讲到如果父盒由于各种原因未设置高度&#xff0c; 子盒的浮动会导致父盒的高度塌陷。为了解决高度塌陷的问题&#xff0c;我们可以添加伪元素。 一、伪元素…

Android 内存优化——常见内存泄露及优化方案

看到了一篇关于内存泄漏的文章后&#xff0c;就想着分享给大家&#xff0c;最后一起学习&#xff0c;一起进步&#xff1a; 如果一个无用对象&#xff08;不需要再使用的对象&#xff09;仍然被其他对象持有引用&#xff0c;造成该对象无法被系统回收&#xff0c;以致该对象在…

【element-tiptap】如何修改选中内容时的背景颜色?

前言&#xff1a;element-tiptap 用鼠标选中内容的时候&#xff0c;背景颜色跟系统设置的主题有关&#xff0c;比如的我的就是卡哇伊的pink&#xff0c;默认是淡蓝色 但是我们观察一下语雀&#xff0c;背景颜色是它规定好的颜色 这篇文章来探索一下&#xff0c;怎么自己规定选…

教学平台的智能化升级:Spring Boot应用

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

除GOF23种设计模式之简单工厂模式

文章目录 1. 简介2. 代码2.1 抽象类&#xff1a;Course.java2.2 产品A:JavaCourse.java2.3 产品B:PythonCourse.java2.4 工厂:CourseFactory.java2.5 测试&#xff1a;Test.java 3. 心得参考链接&#xff08;无&#xff09; 1. 简介 简单工厂模式(Simple Factory Patern):又称…

数据结构4——栈

1. 栈的概念及结构 栈的概念&#xff1a; 栈是一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则…

【SuperHotSwap】IDEA零配置热更新插件升级

往期往期插件v1.0.0发布的时候我发表了一篇文章&#xff0c;如下&#xff1a; 支持功能 如今插件迭代了数个版本&#xff0c;现在迎来了v1.9.0版本的重大升级。如下是支持功能。 支持功能是否支持说明MybatisXML热更新√Class热更新√增强功能需安装dcevm补丁。支持动态新增类…

git rebase的常用场景: 交互式变基, 变基和本地分支基于远端分支的变基

文章目录 作用应用场景场景一&#xff1a;交互式变基(合并同一条线上的提交记录) —— git rebase -i HEAD~2场景二&#xff1a;变基(合并分支) —— git rebase [其他分支名称]场景三&#xff1a;本地分支与远端分支的变基 作用 使git的提交记录变得更加简洁 应用场景 场景…

Java爬虫:获取数据的入门详解

在数字化时代&#xff0c;数据已成为最宝贵的资产之一。无论是市场研究、客户洞察还是产品开发&#xff0c;获取大量数据并从中提取有价值的信息变得至关重要。Java&#xff0c;作为一种成熟且功能强大的编程语言&#xff0c;为编写爬虫提供了强大的支持。Java爬虫可以帮助我们…

如何提高外贸网站在谷歌的收录速度?

外贸企业在进行网络推广时&#xff0c;经常遇到网站页面无法被谷歌快速收录的问题。即使你的网站内容优质、设计精美&#xff0c;如果没有被谷歌收录&#xff0c;就等于失去了被客户发现的机会&#xff0c;GSI谷歌快速收录服务就是为了解决这一问题而诞生的。它不仅能够帮助网站…

5G智慧医疗的实践先锋:SR830-E工业路由器的理性应用

在医疗科技日新月异的今天&#xff0c;5G技术无疑为智慧医疗注入了新的活力。然而&#xff0c;技术的进步不应仅停留在理论层面&#xff0c;更应该在实践中发挥其真正价值。今天&#xff0c;我们就来探讨SR830-E工业路由器如何在实际医疗场景中扮演关键角色&#xff0c;推动5G智…

vscode 远程linux服务器 连接git

vscode 远程linux服务器 连接git 1. git 下载2. git 配置1&#xff09;github 设置2&#xff09;与github建立连接linux端&#xff1a;创建密钥github端&#xff1a;创建ssh key 3. 使用1&#xff09;初始化repository2&#xff09;commit 输入本次提交信息&#xff0c;提交到本…

UE5 圆周运动、贝塞尔曲线运动、贝塞尔曲线点

圆周运动 贝塞尔曲线路径运动 蓝图函数库创建贝塞尔曲线点 // Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "MyBlu…

从MySQL到OceanBase离线数据迁移的实践

本文作者&#xff1a;玉璁&#xff0c;OceanBase 生态产品技术专家。工作十余年&#xff0c;一直在基础架构与中间件领域从事研发工作。现负责OceanBase离线导数产品工具的研发工作&#xff0c;致力于为 OceanBase 建设一套完善的生态工具体系。 背景介绍 在互联网与云数据库技…

【码农必备】CasaOS香橙派安装Code server+cpolar让远程开发更轻松

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…