Java【多线程】(8)CAS与JUC组件


目录

1.前言

2.正文

2.1CAS概念

2.2CAS两种用途

2.2.1实现原子类

2.2.2实现自旋锁

2.3缺陷:ABA问题

2.4JUC组件

2.4.1Callable接口

2.4.2ReentrantLock(与synchronized对比)

2.4.3Semaphore信号量

2.4.4CountDownLatch

3.小结


1.前言

哈喽大家好吖,不知不觉多线程这一块大骨头终于快要啃完了,今天给大家分享的是CAS以及JUC相关组件,那么废话不多说让我们开始吧。

2.正文

2.1CAS概念

核心思想:无所并发控制

CAS(Compare And Swap)是一种基于乐观锁的无锁并发控制技术。其核心逻辑可以概括为:“我认为当前值应该是A,如果是,则更新为B;否则放弃或重试”。整个过程由硬件保证原子性,无需传统锁机制。


通俗来说
假设你和同事协同编辑一份共享文档,每次保存时系统会检查:

  1. 当前内容是否和你打开时的版本一致(预期值比对)。

  2. 如果一致,允许保存;否则提示“内容已变更,请重新编辑”。
    这个过程就是CAS的核心思想——乐观锁:先操作,冲突时重试,而非直接加锁阻塞。


CAS操作的伪代码可以拆解为以下步骤,帮助理解其原子性本质:

// 伪代码:CAS操作的逻辑分解
public boolean compareAndSwap(MemoryAddress addr, int expectedValue, int newValue) {// 1. 读取内存当前值int currentValue = *addr; // 2. 比较当前值与预期值if (currentValue != expectedValue) {return false; // 值已被其他线程修改,操作失败}// 3. 若值未变,执行原子性更新*addr = newValue;return true;
}

2.2CAS两种用途

2.2.1实现原子类

针对原子类,++--这样的操作是原子的,基于CAS实现,不涉及到加锁。


传统实现:

private int count = 0;  
public synchronized void increment() {  count++;  
}  

进阶实现: (使用Java提供的原子类)

AtomicInteger count = new AtomicInteger(0);  
public void increment() {  int oldValue, newValue;  do {  oldValue = count.get();  newValue = oldValue + 1;  } while (!count.compareAndSet(oldValue, newValue)); // CAS自旋  
}  

2.2.2实现自旋锁

先回顾一个上篇文章的概念:自旋锁是线程通过循环(自旋)不断尝试获取锁,而非立即阻塞。适用于锁持有时间极短的场景。

代码实现:

public class CASSpinLock {  private AtomicBoolean locked = new AtomicBoolean(false);  // 获取锁  public void lock() {  while (!locked.compareAndSet(false, true)) {  // 自旋:直到成功将locked从false改为true  }  }  // 释放锁  public void unlock() {  locked.set(false);  }  
}  
  • 线程竞争不激烈时(如短任务),自旋锁比系统锁(如synchronized)更高效。

  • 缺点:长时间自旋会浪费CPU资源(需根据场景权衡)。

2.3缺陷:ABA问题

ABA问题场景

  1. 线程1读取变量值为A

  2. 线程2将值改为B,随后又改回A

  3. 线程1执行CAS操作,发现当前值仍是A,误认为未被修改过,操作成功。


通俗理解:

  • 你看到自己的水杯是满的(A),去接水时离开了一会儿。

  • 期间别人喝光水(A→B)又倒满(B→A)。

  • 你回来后以为水没被喝过,直接喝下(可能喝到别人的水!)。

这里在实际场景中就是非常严重的线程安全的问题了。

解决方案: 

 

1. 版本号标记(AtomicStampedReference)
为值附加一个版本号(类似“修改次数”),CAS时同时校验值和版本号。

AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0);  // 线程1读取值和版本号  
int stamp = ref.getStamp();  
String oldValue = ref.getReference();  // 线程2修改值并更新版本号  
ref.compareAndSet("A", "B", stamp, stamp + 1);  
ref.compareAndSet("B", "A", stamp + 1, stamp + 2);  // 线程1尝试修改:虽然值还是A,但版本号已变,操作失败!  
boolean success = ref.compareAndSet(oldValue, "C", stamp, stamp + 1);  

2. 状态标记(AtomicMarkableReference)
用布尔值标记是否被修改过(简化版版本号)。

2.4JUC组件

2.4.1Callable接口

官方解析:Callable (Java SE 17 & JDK 17)

Callable 是 Java 并发包(JUC)中定义的接口,类似于 Runnable,但允许线程执行任务后返回结果,并可以抛出异常。

与 Runnable 的区别:

  • Runnable 的 run() 没有返回值,Callable 的 call() 可以返回泛型结果。

  • call() 可以抛出受检异常,run() 不能。

具体案例(异步运算1加到100):

Callable<Integer> task = () -> {int sum = 0;for (int i = 1; i <= 100; i++) sum += i;return sum;
};
FutureTask<Integer> futureTask = new FutureTask<>(task);
new Thread(futureTask).start();// 主线程获取结果
System.out.println("计算结果:" + futureTask.get()); // 输出 5050

通过 FutureTask 包装 Callable 任务,启动线程执行后,主线程通过 futureTask.get() 等待结果返回,类似“异步任务+回调”模式。 

2.4.2ReentrantLock(与synchronized对比)

官方解析:ReentrantLock (Java SE 17 & JDK 17)

ReentrantLock 是 JUC 提供的显式锁,支持可重入性、可中断锁、公平锁等特性。

特性synchronizedReentrantLock
锁获取方式隐式(JVM 管理)显式(代码手动加锁/解锁)
可中断不支持支持 lockInterruptibly()
公平锁不支持支持(构造函数指定)
条件变量(Condition)支持(newCondition()

 案例:

class BankAccount {private final ReentrantLock lock = new ReentrantLock();private int balance = 100;void transfer(BankAccount target, int amount) {lock.lock();try {if (this.balance >= amount) {this.balance -= amount;target.balance += amount;}} finally {lock.unlock(); // 必须手动释放锁}}
}

synchronized 的等价实现是在方法签名加 synchronized 关键字,但 ReentrantLock 更灵活:

  • 可设置超时时间(tryLock(1, TimeUnit.SECONDS))。

  • 公平锁减少线程饥饿问题。

2.4.3Semaphore信号量

官方解析:Semaphore (Java SE 17 & JDK 17)

Semaphore 用于控制同时访问某个资源的线程数量,类似“许可证发放”。

核心方法

  • acquire():获取许可证(若无可用则阻塞)。

  • release():释放许可证。

 案例:(模拟停车场)

Semaphore semaphore = new Semaphore(3); // 3 个许可证Runnable parkAction = () -> {try {semaphore.acquire(); // 获取车位System.out.println(Thread.currentThread().getName() + " 停入车位");Thread.sleep(2000); // 停车 2 秒} catch (InterruptedException e) {e.printStackTrace();} finally {semaphore.release(); // 释放车位System.out.println(Thread.currentThread().getName() + " 离开车位");}
};// 启动 5 辆车尝试停车
for (int i = 0; i < 5; i++) {new Thread(parkAction).start();
}

2.4.4CountDownLatch

官方解析:CountDownLatch (Java SE 17 & JDK 17)

CountDownLatch 是一个同步工具,允许一个或多个线程等待其他线程完成操作。

核心方法:

  • countDown():计数器减 1。

  • await():阻塞直到计数器归零。 

public static void main(String[] args) {CountDownLatch latch = new CountDownLatch(3); // 需要等待 3 个任务// 资源加载任务Runnable loadTask = () -> {try {Thread.sleep((long) (Math.random() * 2000));System.out.println(Thread.currentThread().getName() + " 加载完成");latch.countDown();} catch (InterruptedException e) {e.printStackTrace();}};// 启动 3 个资源加载线程new Thread(loadTask, "地图").start();new Thread(loadTask, "音效").start();new Thread(loadTask, "UI").start();// 主线程等待所有资源加载完成try {latch.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("所有资源加载完成,开始游戏!");}

3.小结

今天的分享到这里就结束了,喜欢的小伙伴点点赞点点关注,你的支持就是对我最大的鼓励,大家加油!

 

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

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

相关文章

【Docker】离线安装Docker

背景 离线安装Docker的必要性&#xff0c;第一&#xff0c;在目前数据安全升级的情况下&#xff0c;很多外网已经基本不好访问了。第二&#xff0c;如果公司有对外部署的需求&#xff0c;那么难免会存在对方只有内网的情况&#xff0c;那么我们就要做到学会离线安装。 下载安…

MecAgent Copilot:机械设计师的AI助手,开启“氛围建模”新时代

MecAgent Copilot作为机械设计师的AI助手,正通过多项核心技术推动机械设计进入“氛围建模”新时代。以下从功能特性、技术支撑和应用场景三方面解析其创新价值: 一、核心功能特性 ​​智能草图生成与参数化建模​​ 支持自然语言输入生成设计草图和3D模型,如输入“剖面透视…

MCU屏和RGB屏

一、MCU屏 MCU屏‌&#xff1a;全称为单片机控制屏&#xff08;Microcontroller Unit Screen&#xff09;&#xff0c;在显示屏背后集成了单片机控制器&#xff0c;因此&#xff0c;MCU屏里面有专用的驱动芯片。驱动芯片如&#xff1a;ILI9488、ILI9341、SSD1963等。驱动芯片里…

7.5 使用MobileNet v3进行图像的区分

MobileNet v3是Google在2019年提出的轻量级卷积神经网络结构,旨在提高在移动设备上的速度和准确性,广泛的用于轻量级网络。 MobileNet v3-Small的网络结构如下,它的输入是224x224的3通道彩色图片。 使用过程如下: 1.创建模型、修改最终分类数量 #1.创建mobilenet_v3_small…

构建面向大模型训练与部署的一体化架构:从文档解析到智能调度

作者&#xff1a;汪玉珠&#xff5c;算法架构师 标签&#xff1a;大模型训练、数据集构建、GRPO、自监督聚类、指令调度系统、Qwen、LLaMA3 &#x1f9ed; 背景与挑战 随着 Qwen、LLaMA3 等开源大模型不断进化&#xff0c;行业逐渐从“能跑通”迈向“如何高效训练与部署”的阶…

PostgreSQL技术大讲堂 - 第86讲:数据安全之--data_checksums天使与魔鬼

PostgreSQL技术大讲堂 - 第86讲&#xff0c;主题&#xff1a;数据安全之--data_checksums天使与魔鬼 1、data_checksums特性 2、避开DML规则&#xff0c;嫁接非法数据并合法化 3、避开约束规则&#xff0c;嫁接非法数据到表中 4、避开数据检查&#xff0c;读取坏块中的数据…

【机器学习】机器学习笔记

1 机器学习定义 计算机程序从经验E中学习&#xff0c;解决某一任务T&#xff0c;进行某一性能P&#xff0c;通过P测定在T上的表现因经验E而提高。 eg&#xff1a;跳棋程序 E&#xff1a; 程序自身下的上万盘棋局 T&#xff1a; 下跳棋 P&#xff1a; 与新对手下跳棋时赢的概率…

Ubuntu20.04 设置开机自启

参考&#xff1a; Ubuntu20.04 设置开机自启_ubuntu进bos系统-CSDN博客

数据库中存储过程的流程语句讲解

一、流程语句讲解 二、总结 一、流程语句讲解 1.1 if语句讲解 语法&#xff1a; IF condition THENstatements; ELSEIF condition THENstatements; ELSEstatements; END IF; 题目示例&#xff1a; # 判断成绩等级 # 输入学生的编号,取出学生的第一门课&#xff0c;然后判断…

kubernetes》》k8s》》ConfigMap 、Secret

configmap官网 ConfigMap是一种 API 对象&#xff0c;使用时&#xff0c; Pods 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。ConfigMap将配置和Pod解耦&#xff0c;更易于配置文件的更改和管理。ConfigMap 并不提供保密或者加密功能。 如果你想存储的数据是机密的…

git在IDEA中使用技巧

git在IDEA中使用技巧 merge和rebase 参考&#xff1a;IDEA小技巧-Git的使用 git回滚、强推、代码找回 参考&#xff1a;https://www.bilibili.com/video/BV1Wa411a7Ek?spm_id_from333.788.videopod.sections&vd_source2f73252e51731cad48853e9c70337d8e cherry pick …

Spring 事务失效的原因及解决方案全解析,来复习了

Spring 事务失效是指在使用 Spring 声明式事务管理时&#xff0c;预期的事务行为&#xff08;如事务的开启、提交、回滚等&#xff09;未按预期执行&#xff0c;导致数据操作未满足 ACID 特性&#xff08;原子性、一致性、隔离性、持久性&#xff09;&#xff0c;从而引发数据不…

「出海匠」借助CloudPilot AI实现AWS降本60%,支撑AI电商高速增长

&#x1f50e;公司简介 「出海匠」&#xff08;chuhaijiang.com&#xff09;是「数绘星云」公司打造的社交内容电商服务平台&#xff0c;专注于为跨境生态参与者提供数据支持与智能化工作流。平台基于大数据与 AI 技术&#xff0c;帮助商家精准分析市场趋势、优化运营策略&…

python每日一练

题目一 输入10个整数,输出其中不同的数,即如果一个数出现了多次,只输出一次(要求按照每一个不同的数第一次出现的顺序输出)。 解题 错误题解 a list(map(int,input().split())) b [] b.append(a[i]) for i in range(2,11):if a[i] not in b:b.append(a[i]) print(b)但是会…

Docker实战:从零构建高可用的MySQL主从集群与Redis集群

在分布式系统架构中&#xff0c;数据库集群是保障数据高可用和性能的关键组件。本文将通过Docker技术&#xff0c;手把手教你搭建MySQL主从集群和Redis Cluster&#xff0c;并分享独创的优化技巧与运维实战经验。 一、为什么选择Docker部署集群&#xff1f; 传统数据库集群搭…

STM32电机库 电机控制特性

ST MC FW库提供FOC和六步法两种电机控制方式。这使得它能够驱动永磁同步电机 (PMSM) 和无刷直流电机 (BLDC)。FOC 更适合 PMSM,而六步法更适合 BLDC 电机。该固件可以驱动内嵌式PMSM 和标贴式PMSM。 ST Motor Control 固件库提供以下功能: FOC SVPWM 生成: 可配置的 PW…

Go:方法

方法声明 type point struct { X, Y float64 }// 普通函数 func Distance(p, q Point) float64 {return math.Hypot(q.x - p.x, q.y - p.Y) }// Point类型的方法 func (p Point) Distance(q Point) float64 {return math.Hypot(q.x - p.x, q.y - p.Y) }方法声明与普通函数声…

前端基础之《Vue(4)—响应式原理》

一、什么是响应式 1、响应式英文reactive 当你get/set一个变量时&#xff0c;你有办法可以“捕获到”这种行为。 2、一个普通对象和一个响应式对象对比 &#xff08;1&#xff09;普通对象 <script>// 这种普通对象不具备响应式var obj1 {a: 1,b: 2} </script>…

【技术派部署篇】Windows本地部署技术派

一、技术派简介 技术派是一个采用 Spring Boot、MyBatis-Plus、MySQL、Redis、ElasticSearch、MongoDB、Docker、RabbitMQ 等技术栈的社区系统&#xff0c;其 1.0 版已正式上线。该项目的技术栈按阶段集成引入&#xff0c;开发者可根据自身需求选择不同版本进行学习。 二、环…

DeepSeek和ChatGPT的全面对比

DeepSeek和ChatGPT作为当前领先的大语言模型&#xff0c;代表了AI发展的不同技术路径和应用理念。以下从技术架构到用户体验的全面对比分析&#xff0c;将揭示两者在AI竞赛中的独特定位。 一、模型架构与原理 1. DeepSeek 架构特点&#xff1a;采用混合专家系统&#xff08;…