JUC包下的原子类的实现方法

网络工程师软考通关指南:网络新技术与应用深度解析 网络安全与管理是网络工程师必须掌握的核心技能,华为设备在企业网络中广泛应用。建议考生在理解安全原理的基础上,重点掌握华为特有的命令体系和配置方法,通过模拟实验加深理解。下篇文章将深入讲解"网络优化与QoS"章节,涵盖流量调度、拥塞避免、服务质量等关键技术,敬请期待。 阅读详情
class AccountSafe implements Account {
 private AtomicInteger balance;
 public AccountSafe(Integer balance) {
 this.balance = new AtomicInteger(balance);
  }
 @Override
 public Integer getBalance() {
 return balance.get();
 }
 @Override
 public void withdraw(Integer amount) {
 while (true) {
 int prev = balance.get();
 int next = prev - amount;
 if (balance.compareAndSet(prev, next)) {
 break;
 }
 }
 // 可以简化为下面的方法
 // balance.addAndGet(-1 * amount);
 }
}

前面看到的 AtomicInteger 的解决方法,内部并没有用锁来保护共享变量的线程安全。那么它是如何实现的呢?

public void withdraw(Integer amount) {
 while(true) {
 // 需要不断尝试,直到成功为止
 while (true) {
 // 比如拿到了旧值 1000
 int prev = balance.get();
 // 在这个基础上 1000-10 = 990
 int next = prev - amount;
 /*
 compareAndSet 正是做这个检查,在 set 前,先比较 prev 与当前值
 - 不一致了,next 作废,返回 false 表示失败
 比如,别的线程已经做了减法,当前值已经被减成了 990
 那么本线程的这次 990 就作废了,进入 while 下次循环重试
 - 一致,以 next 设置为新值,返回 true 表示成功
 */
 if (balance.compareAndSet(prev, next)) {
 break;
 }
 }
 }
}

其中的关键是 compareAndSet,它的简称就是 CAS (也有 Compare And Swap 的说法),它必须是原子操作。

在这里插入图片描述
其实 CAS 的底层是 lock cmpxchg 指令(X86 架构),在单核 CPU 和多核 CPU 下都能够保证【比较-交换】的原子性。
在多核状态下,某个核执行到带 lock 的指令时,CPU 会让总线锁住,当这个核把此指令执行完毕,再开启总线。这个过程中不会被线程的调度机制所打断,保证了多个线程对内存操作的准确性,是原子的。

volatile

获取共享变量时,为了保证该变量的可见性,需要使用 volatile 修饰。
它可以用来修饰成员变量和静态成员变量,他可以避免线程从自己的工作缓存中查找变量的值,必须到主存中获取它的值,线程操作 volatile 变量都是直接操作主存。即一个线程对 volatile 变量的修改,对另一个线程可见。
注意
volatile 仅仅保证了共享变量的可见性,让其它线程能够看到最新值,但不能解决指令交错问题(不能保证原子性)
CAS 必须借助 volatile 才能读取到共享变量的最新值来实现【比较并交换】的效果

为什么无锁效率高

无锁情况下,即使重试失败,线程始终在高速运行,没有停歇,在synchronized 会让线程在没有获得锁的时候,发生上下文切换,进入阻塞。打个比喻线程就好像高速跑道上的赛车,高速运行时,速度超快,一旦发生上下文切换,就好比赛车要减速、熄火,等被唤醒又得重新打火、启动、加速… 恢复到高速运行,代价比较大。
但无锁情况下,因为线程要保持运行,需要额外 CPU 的支持,CPU 在这里就好比高速跑道,没有额外的跑道,线程想高速运行也无从谈起,虽然不会进入阻塞,但由于没有分到时间片,仍然会进入可运行状态,还是会导致上下文切换。

CAS 的特点

结合 CAS 和 volatile 可以实现无锁并发,适用于线程数少、多核 CPU 的场景下。
CAS 是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算改了也没关系,我吃亏点再重试呗。
synchronized 是基于悲观锁的思想:最悲观的估计,得防着其它线程来修改共享变量,我上了锁你们都别想改,我改完了解开锁,你们才有机会。
CAS 体现的是无锁并发、无阻塞并发,请仔细体会这两句话的意思
因为没有使用 synchronized,所以线程不会陷入阻塞,这是效率提升的因素之一
但如果竞争激烈,可以想到重试必然频繁发生,反而效率会受影响

AtomicReference
AtomicMarkableReference
AtomicStampedReference

ABA 问题及解决

主线程仅能判断出共享变量的值与最初值 A 是否相同,不能感知到这种从 A 改为 B 又 改回 A 的情况,如果主线程希望:
只要有其它线程【动过了】共享变量,那么自己的 cas 就算失败,这时,仅比较值是不够的,需要再加一个版本号
AtomicStampedReference

Unsafe

Unsafe 对象提供了非常底层的,操作内存、线程的方法,Unsafe 对象不能直接调用,只能通过反射获得

使用 Python 爬取 Wikipedia 数据:抓取百科条目及其内容 维基百科的 API 提供了一些方便的接口,通过这些接口,我们可以轻松获取到维基百科的条目、类别、图片和其他相关信息。维基百科的 API 主要是基于 HTTP 请求的,通过向特定的 URL 发送 GET 请求来获取信息。:获取指定条目的内容。在本博客中,我们介绍了如何使用 Python 爬取维基百科的条目数据。通过使用 Wikipedia API 和网页抓取技术,我们能够高效地获取条目内容,并将其存储和分析。希望本篇教程能帮助你深入理解如何抓取和处理维基百科的数据。 阅读详情

相关推荐

Microsoft Defender防病毒扫描添加排除项

Win10与Win11上的“**Microsoft Defender防病毒**”功能默认会自动扫描所有非压缩文件,如果发现病毒或疑似病毒甚至经过手动修改后某些安装文件,会自动将其删除,如果是后面两种情况,则可能会造成误报,对我们正常办公或学习造成不利影响。 此时, 我们可以将某个目录或文件设置为“**Microsoft Defender防病毒不会扫描已排除的项目**”(<red>但要注意:这些被排除的目录或文件会给笔记本造成一定的安全风险,如果真有病毒感染这些目录或文件它们也不会被“**Micr

weixin_42148668的博客 6481

CAS与volatile组合拳 无锁怎么保证线程安全的

CAS与volatile组合拳 无锁怎么保证线程安全的

iqqcode 1260

双击文件夹弹窗“找不到应用程序”,但是右键点击打开可以

此电脑、回收站、c、d、f盘、控制面板、任意文件夹等都没有办法双击打开。 右键中包含“使用filemanager打开”,是由于FileManager卸载残留导致的。 懒人专用附件 下载解压上面附件,双击导入可以清理FileManager软件残留 参考: 双击此电脑出现找不到应用程序,但是右键点击可以-其他-优快云问答https://ask.youkuaiyun.com/questions/7631439 电脑上的文件夹双击都提示找不到应用程序,但是右击打开就能打开,该怎么解决? - 知乎 (z

webmasterqpwou的博客 1万+

Java并发编程-CAS乐观锁

主要介绍了Java并发编程中的CAS乐观锁。

weixin_56446161的博客 434

如何实现SOLIDWORKS阵列的“智能变更”?

有时,我们在设计一个零件时,零件上有一排阵列孔,同时零件有不同的长度,我们又希望可以做到零件长度改变时,这排孔可以按长度等距增减孔阵列的个数;或是零件长度加长或缩短时,这排孔保持个数不变,按零件长度增减孔距。 那具体要怎么做呢?接下来,我们一起来看看怎么用SOLIDWORKS中简单的操作来实现这两种智能的变更: 零件长度加长或缩短时,这排孔要按长度等距增减孔阵列的个数。 零件长度加长或缩短时,这排孔保持个数不变,按零件长度增减孔距。 那接下来,我们一起来看看怎么用简单的操作来实现这两种智能的

SOLIDWORKS艾金米 2077

Halcon异常检测训练避坑指南:如何避免GPU内存溢出和样本不足问题

本文针对Halcon深度学习异常检测训练中常见的GPU内存溢出和样本不足两大难题,提供了从原理分析到实战解决方案的深度指南。通过调整批次大小、图像尺寸、使用梯度累积等技巧有效管理显存,并利用针对性数据增强与人工合成策略破解小样本困境,帮助开发者构建稳定高效的训练流程。

river的博客 215

谈谈你对volatile的理解

一、volatile特性: volatile是Java虚拟机提供的轻量级的同步机制。主要有三大特性: 保证可见性 不保证原子性 禁止指令重排序 1、保证可见性 1)代码演示 AAA线程修改变量number的值为60,main线程获取到的number值是0,就一直循环等待。 原因:int number = 0;number变量之前没有添加volatile关键字,没有可见性。添加volatile关键字...

MrShanQIu的博客 506

YOLOv11架构革新:华为VanillaNet与BiFPN深度融合的突破性改进实战指南

购买即可解锁300+YOLO优化文章,并且还有海量深度学习复现项目,价格仅需两杯奶茶的钱,别人有的本专栏也有!

LXY_LOVE36的博客 136

CAS(Compare and swap)

原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割而只执行其中的一部分(不可中断性)。将整个操作视作一个整体,资源在该次操作中保持一致,这是原子性的核心特征。 CAS(Compare and swap) Compare and swap 比较和交换。属于硬件同步原语, 处理器提供了基本内存操作的原子性保证。 CAS操作需要输入两个数值,一个是旧值A(期望操作前的值)和一个新值B,在操作期间先对旧值进行比较,若没有发生变化,才交换成新值,发生了变化则不变换。 JAVA中的.

qq_42266891的博客 314

28-3 文件上传漏洞 -白盒审计绕过

这行代码是用来获取文件名中最后一个点(.)后的部分,也就是文件的后缀名。这个函数会返回以最后一个点(.)开始到字符串末尾的部分,包括点(.)本身。然而,这段代码存在一个潜在的安全风险。攻击者可以利用多个点(.)来构造恶意文件名,以绕过后缀名检查。切换到bp将抓到的上传请求发送到重发器然后改包。先上传一个普通的php文件然后使用bp抓包。

weixin_43263566的博客 392

vscode中运行gcc -v命令失败了,提示:gcc不是内部或外部命令...如何解决?

🏆本文收录于 《全栈Bug调优(实战版)》 专栏,该专栏专注于分享我在真实项目开发中遇到的各类疑难Bug及其深层成因,并系统提供高效、可复现的解决思路和实操方案。无论你是刚入行的新手开发者,还是拥有多年项目经验的资深工程师,本专栏都将为你提供一条系统化、高质量的问题排查与优化路径,助力你加速成长,攻克技术壁垒,迈向技术价值最大化与职业发展的更高峰🚀!

**My Coding Family** 976

理解volatile和CAS配合使用原理

volatile关键字 主要是让被修饰的对象能够在内存中及时的可见,修改后及时传递到各个线程的本地内存中。 举一个例子最清晰,A和B线程同时去操作一个 int值 都去加1 如下图:最开始两个线程都从cpu的内存空间中去拿到count的值放到自己的本地内存中 如果不是使用关键字volatile 可能导致如果A线程先执行完后把count值修改成了1并且刷新到了主内存空间,B线程再执行的时候本...

liaoxiaolin520的博客 4204

基于STM32L4XX、HAL库的ICP-10111压力传感器驱动程序设计

define ICP10111_CMD_MEAS_ULN 0x7866 // 超低噪声模式。#define ICP10111_CMD_MEAS_LP 0x609C // 低功耗模式。#define ICP10111_CMD_MEAS_LN 0x70DF // 低噪声模式。#define ICP10111_CMD_MEAS_N 0x6825 // 正常模式。ICP10111_MODE_LN, // 低噪声。// 等待测量完成(根据模式不同等待时间不同)

zhusl6688的博客 416

26.原子类操作类

JDK1.5之前,为了保证Java中对单个变量的多个独立操作的原子性和安全性,通常会使用到synchronized锁,但是synchronized需要底层操作系统mutex资源的支持,这是一种重量级资源,性能比较低!JDK1.5的时候,新增了JUC包,增加了许多和同步有关的特性,大大提高了使用Java进行并发编程的效率,比如并发集合、并发队列、新lock锁等。

纵横千里 捭阖四方 的专栏 360

VC中sqlite的使用

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

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

JAVA并发编程(十三)JUC下原子变量操作类AtomicLong源码分析

JAVA并发编程(十三)JUC下原子变量操作类AtomicLong源码分析JAVA并发编程(十三)JUC下原子变量操作类AtomicLong源码分析1.1 什么是原子变量操作类?1.2 AtomicLong源码分析1.2.1递增递减操作1.2.2 boolean comapreAndSet(long expect , long update)方法1.2.3 简单应用实例 JAVA并发编程(十三)J...

qq_43080270的博客 454

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

【源码】JUC —— AtomicInteger 解读

【源码】JUC —— AtomicInteger 解读前言版本UnsafeAtomicInteger属性及构造原子操作getAndSetcompareAndSetgetAndXXXXXXAndGetUpdateAccumulate类型转换demo总结 前言 JUC 下提供了大量的 原子操作类,以保证我们可以便捷的操作对应类型且保证 并发环境 下的 原子性。本章节介绍 AtomicInteger 版本 JDK11 Unsafe 底层的操作基本都由 Unsafe 类提供,比如 CAS操作 @HotSpotI

小水牛的博客 802

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Java多线程基础 08.JUC包下的AtomicXXX类

文章目录Java多线程基础 08.AtomicInteger、AtomicLong、AtomicObjectAtomicXXX原子性测试AtomicInteger原理解析AtomicLong、AtomicObject原理解析AtomicBoolean原理解析 Java多线程基础 08.AtomicInteger、AtomicLong、AtomicObject AtomicXXX   java.util.concurrent.atomic包下有着许多AtomicXXX命名的类。这些类基于Unsafe的cas方

努力推石头的西西弗斯 612

并发包中的原子类

跟着这个错误我们可以找到,当加载我们自定义的这个类的时候,使用的是我们的应用程序类加载器AppClassLoador。看完这个例子之后我们再来总结一下CAS算法,就是通过变量在实例中的内存偏移量拿到这个变量在内存中此时此刻的值,如果与之前拿到这个变量的旧值相等,说明没有线程对他做修改,可以修改成我们期待的新值。我一开始想的是使用引导类加载器来加载自定义的这个类,利用类加载的传到规则不就可以使用启动类来加载这个Unsafe类吗,但是试了几次没有成功,换一种方式,利用反射,利用反射去获得这个实例。...

最后的武艺集大成者 444

Java并发JUC原子类

Java并发JUC原子类

jsjxb的博客 123

java多线程(3):JUC基础概述

几个基本概念 volatile,不保证原子性,只保证可见性,也就说不能保证线程安全。 如果是一写多读,那么jvm可以解决同步问题。但是,如果是多写,则线程并非安全。 实现原理是禁止指令重排序,并强制线程从主存储器获取数据。具体实现原理是在该数据发生更改时,线程会立刻将其写回主存。其他cpu都在嗅探主存储器写总线,当发现自己持有的缓存被修改时,对自己的缓存做无效处理,在下次访问时直接从主存储器...

define_us的专栏 495

JUC (java. util.concurrent) 的常见类及创建新线程的方法等 [Java EE 初阶]

/ 如果多个线程去读取, 本身不会有任何线程安全问题, 一旦有线程修改, 就会把自身复制一份, 尤其修改如果比较耗时的话, 其他线程还是从旧的数据上读取, 一旦修改成功, 使用新的 ArrayList (本质上就是引用的重新赋值, 速度极快, 并且又是原子的), 这个过程中没有引入任何的加锁操作, 使用了 创建副本 => 修改副本 => 使用副本替换, 类似于显卡渲染画面。// 当计数器数值为 0 的时候, 继续 P 操作, 就会阻塞等待, 一直等待到其他线程执行了 V 操作, 释放了一个空闲资源为止。

zjt_2002的博客 1208

Java中的CAS实现原理

java中的CAS实现

SO_zxn的博客 951

博客文章目录

快速浏览博客内容

爪哇岛咖啡种植农场 425

Java并发相关文章说明

 对于Java并发这一块的知识,一直一来都是东一块西一块的,自己没有进行一次整体,自己的笔记也是有点凌乱。就想着整理一份完整的出来,参考源码跟资料进行整理。同时也监督自己养成一个好的周期性写博客的习惯。一下是对于相关知识的整理,如果缺少什么可以进行留言,我会进行补充。 1.并发相关的原子性,可见性,顺序一致性,happen-before 2.volatile关键字的作用和汇编原理 3.synchr...

szhlcy的博客 142

JUC并发编程详解

1、什么是JUC? java.util.concurrnet java.util.concurrent.atomic java.util.concurrent.locks 2、进程和线程 进程:一个程序的实例 线程:是一个进程的实体,CPU调度和分配的基本单位 java默认有两个线程,main方法和GC 开启线程的方式:Thread、Runnable、Callable Java本质是无法开启线程的,是调用本地方法(c++)来开启线程的,java无法操作硬件。 3、并发、并行 并发编程:

m0_68006260的博客 859

15.JUC原子类

基础原子类(以AtomicInteger为例),主要是通过CAS自旋 + volatile相结合的方案实现,既保证了变量操作线程的原子性,有避免了synchronized重量级锁的开销,使得Java程序的效率得到大幅度提升。基础原子类型 只能保证一个变量的原子操作,但是当需要对多个变量操作时,CAS无法保证原子性操作,这个时候可以使用AtomicReference(原子引用类型),保证对象引用的原子性。属性更新原子类是Java并发包提供的一组类,用于原子性地更新对象中的属性值。

q1372302825的博客 1217
上一篇: synchronized的底层原理以及锁膨胀对应的JMM模型
下一篇: 原子累加器 LongAdde
KILLBILLKILLING
博客等级 码龄8年 3粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值