Java并发 - 原子类

CAS 原子操作

CAS(Compare and Swap)是一种并发算法,通常用于实现多线程环境下的同步操作,特别是在并发编程中实现无锁算法。CAS操作涉及三个参数:内存位置(V)、期望值(A)和新值(B)。操作的意义是:仅当V的值等于A时,才将V的值更新为B。整个操作是原子的,不会被其他线程中断。

下面是CAS的基本原理:

  1. 读取内存值(V): 线程首先读取共享变量的当前值(V)。
  2. 比较并交换(Compare and Swap): 线程比较读取的值(V)与预期的值(A)。如果相等,说明在读取值的过程中没有其他线程对该变量进行修改,那么线程将新值(B)写入内存位置;否则,说明有其他线程对该变量进行了修改,CAS操作失败,线程需要重新尝试。
  3. 原子性保证: 整个比较并交换的过程是原子性的,即在整个操作过程中,不会被其他线程中断。

CAS优点:

​ 避免了使用锁带来的性能开销,因为它不会使线程阻塞,而是采用乐观的方式尝试更新共享变量

CAS缺点:

  1. ABA问题: 如果一个变量原来的值是A,线程1将其改为B,然后又改回A,此时线程2通过CAS检查发现值仍然是A,认为没有被修改,但实际上已经发生了变化。为了解决ABA问题,可以使用版本号等方式引入更多信息。
  2. 循环时间长开销大:CAS操作失败时,线程需要不断地重试,直到成功为止。这可能导致一些线程长时间无法完成操作,增加了开销。
  3. 只能保证一个共享变量的原子操作: CAS只能对单一的共享变量进行原子操作,无法支持类似于整个事务的复合操作。

CAS 示例

public class CASExample {public static void main(String[] args) {// 创建一个AtomicInteger,初始值为0AtomicInteger atomicInteger = new AtomicInteger(0);// 执行CAS操作,尝试将值从0更新为1boolean casResult = atomicInteger.compareAndSet(0, 1);if (casResult) {System.out.println("CAS success. new value: " + atomicInteger.get());} else {System.out.println("CAS failed.");}// 尝试再次执行CAS操作,将值从0更新为2,但由于当前值已经是1,操作会失败casResult = atomicInteger.compareAndSet(0, 2);if (casResult) {System.out.println("CAS successful. new value: " + atomicInteger.get());} else {System.out.println("CAS failed.");}}
}
Connected to the target VM, address: '127.0.0.1:64335', transport: 'socket'
CAS success. new value: 1
CAS failed.

UnSafe 原子操作

Unsafe 类是 Java 中的一个非常特殊且强大的类,它提供了直接访问内存和执行 CAS(Compare and Swap)等底层操作的方法。然而,Unsafe 类并不是官方公开的 API,并且在 Java 9 中进行了限制,不再推荐使用。因此,如果可能,最好避免直接使用 Unsafe 类。

以下是一些 Unsafe 类的主要功能:

  1. 内存操作: Unsafe 类提供了一些方法,可以直接操作内存,如allocateMemoryfreeMemoryputXXXgetXXX 等方法,其中 XXX 表示不同的数据类型。
  2. 对象操作: Unsafe 类允许直接操作对象的内部字段,比如获取和设置字段的值,甚至可以直接修改对象的类。这些操作可能绕过了 Java 的访问权限检查。
  3. CAS 操作: Unsafe 类提供了 CAS 相关的方法,例如 compareAndSwapIntcompareAndSwapLongcompareAndSwapObject 等,用于实现无锁算法。
  4. 数组操作: Unsafe 提供了一系列用于操作数组元素的方法,例如 putIntVolatilegetIntVolatile 等。
  5. 类加载: Unsafe 类还提供了一些用于加载类和定义类的方法。

AtomicInteger

AtomicInteger 是一种用于执行原子操作的整型类。它常用于在多线程环境下对计数器进行操作。

int get() 				// 获取当前 AtomicInteger 对象的当前值。
void set(int newValue) 	// 设置 AtomicInteger 对象的值为指定的新值。
int getAndIncrement()   // 原子性地将当前值加 1,并返回加 1 前的值
int incrementAndGet()   // 原子性地将当前值加 1,并返回加 1 后的值。
boolean compareAndSet(int expect, int update)   // 如果当前值等于预期值 expect,则将当前值更新为新值 update,返回更新是否成功的结果。
int addAndGet(int delta)// 原子性地将当前值与给定的增量 delta 相加,并返回相加后的值。
void lazySet(int newValue) //使用lazySet设置值后,其他线程可能会在之后的一小段时间内读到的还是旧值,更新为newValue有延迟。

AtomicInteger使用示例

import java.util.concurrent.atomic.AtomicInteger;public class AtomicIntegerExample {public static void main(String[] args) {AtomicInteger counter = new AtomicInteger(0);// 原子性地增加计数器值int incrementedValue = counter.incrementAndGet();System.out.println("Incremented Value: " + incrementedValue);}
}

AtomicBoolean

AtomicBoolean 提供对布尔类型变量的原子操作,通常用于在多线程环境下实现一些状态标记。

// 获取当前 AtomicBoolean 对象的当前值。
boolean get()
// 设置 AtomicBoolean 对象的值为指定的新值。
void set(boolean newValue)
// 原子性地设置 AtomicBoolean 对象的新值,并返回设置前的旧值。
boolean getAndSet(boolean newValue)
// 如果当前值等于预期值 expect,则将当前值更新为新值 update,返回更新是否成功的结果。
boolean compareAndSet(boolean expect, boolean update)
// 与 compareAndSet 方法类似,但不一定提供强制的内存同步。
boolean weakCompareAndSet(boolean expect, boolean update)

AtomicBoolean使用示例

import java.util.concurrent.atomic.AtomicBoolean;public class AtomicBooleanExample {public static void main(String[] args) {AtomicBoolean flag = new AtomicBoolean(true);// 原子性地将标志值设置为falseflag.compareAndSet(true, false);System.out.println("Flag Value: " + flag.get());}
}

AtomicReference

AtomicReference 允许原子性地操作引用类型变量。下面是一个示例,演示如何原子性地更新引用值

AtomicReference(V initialValue) // 构造函数,创建一个AtomicReference实例,初始值为initialValue。
V get()	// 获取当前引用的值。
void set(V newValue)	// 设置当前引用的值为newValue。
boolean compareAndSet(V expect, V update)	// 如果当前引用的值等于expect,则将当前引用的值设置为update,返回true;否则,返回false。
V getAndSet(V newValue)	// 设置当前引用的值为newValue,并返回先前的值。
boolean weakCompareAndSet(V expect, V update)	// 类似于compareAndSet,但是对于某些实现,不保证对 expect 和 update 的原子性检查。
String toString() // 返回当前引用的字符串表示形式。

AtomicReference使用示例

import java.util.concurrent.atomic.AtomicReference;public class AtomicReferenceExample {public static void main(String[] args) {AtomicReference<String> reference = new AtomicReference<>("initialValue");// 如果当前值为"initialValue",则设置为"newValue"reference.compareAndSet("initialValue", "newValue");System.out.println("Reference Value: " + reference.get());}
}

AtomicStampedReference

AtomicStampedReferenceAtomicReference 的基础上增加了版本号,用于解决ABA问题。

// 构造方法
AtomicStampedReference(V initialRef, int initialStamp)
// 返回当前引用
V getReference()
// 返回当前标记
int getStamp()
// 返回当前引用,并将当前标记存储在 stampHolder[0] 中
V get(int[] stampHolder)
// 如果当前引用和标记与 expectedReference、expectedStamp 相等,则使用 newReference 和 newStamp 更新引用和标记。该方法在CAS操作的基础上进行判断,避免了ABA问题。
boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp)
// 与 compareAndSet 方法相同,但被声明为 weak,通常在不需要保证线程间同步的场景使用。
boolean weakCompareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp)

AtomicStampedReference使用示例

import java.util.concurrent.atomic.AtomicStampedReference;public class AtomicStampedReferenceExample {public static void main(String[] args) {AtomicStampedReference<String> stampedReference = new AtomicStampedReference<>("initialValue", 0);// 如果当前值为"initialValue"且版本号为0,则设置为"newValue"和版本号1stampedReference.compareAndSet("initialValue", "newValue", 0, 1);System.out.println("Stamped Reference Value: " + stampedReference.getReference());System.out.println("Stamped Reference Stamp: " + stampedReference.getStamp());}
}

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

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

相关文章

数据仓库 Apache Hive

一、数据分析 1、数据仓库 数据仓库&#xff08;英语&#xff1a;Data Warehouse&#xff0c;简称数仓、DW&#xff09;&#xff0c;是一个用于存储、分析、报告的数据系统。 数据仓库的目的是构建面向分析的集成化数据环境&#xff0c;分析结果为企业提供决策支持&#xff08…

Unity 编辑器篇|(四)编辑器拓展GUI类 (全面总结 | 建议收藏)

目录 1. 前言2. 参数2.1 静态变量2.2 静态函数2.3 委托 3. 功能3.1 按钮&#xff1a;Button、RepeatButton3.2 文本&#xff1a;Label 、TextField 、TextArea 、PasswordField3.3 滑动条&#xff1a;HorizontalScrollbar 、VerticalScrollbar3.4 滑条&#xff1a;VerticalSlid…

Java基础(抽象类)

文章目录 一、抽象类特性代码示例 二、抽象类注意事项三、抽象类和接口的比较 刚刚学了Python的多态和抽象类&#xff0c;就想着跟Java的比对一下。 一、抽象类特性 抽象类不能被实例化&#xff1a;抽象类只能用作其他类的基类&#xff0c;不能直接创建实例。子类必须实现所有…

表单生成器基于(form-create-designer+ant design vue)

效果展示 1.源码地址&#xff1a; 前端&#xff1a;https://gitee.com/houshixin/form-design-ui 后端&#xff1a;https://gitee.com/houshixin/form-design-web 2.单独使用前端的时候就把请前后台的接口注释就可以 3.都启动的话&#xff1a; 1&#xff09;.先导入数据库 2.表…

3. Mybatis 中SQL 执行原理

2. Mybatis 中SQL 执行原理 这里有两种方式&#xff0c;一种为常用的 Spring 依赖注入 Mapper 的方式。另一种为直接使用 SqlSessionTemplate 执行 Sql 的方式。 Spring 依赖注入 Mapper 的方式 Mapper 接口注入 SpringIOC 容器 Spring 容器在扫描 BeanDefinition 阶段会扫…

C++代码重用:继承与组合的比较

目录 一、简介 继承 组合 二、继承 三、组合 四、案例说明 4.1一个电子商务系统 4.1.1继承方式 在上述代码中&#xff0c;Order类继承自User类。通过继承&#xff0c;Order类获得了User类的成员函数和成员变量&#xff0c;并且可以添加自己的特性。我们重写了displayI…

C# 关于当ObservableCollection增删查改元素时,触发事件用例

ObservableCollection 类提供了一种实时监测集合变化的机制&#xff0c;可以通过订阅 CollectionChanged 事件来响应集合的添加、移除和重置等变化。 using System; using System.Collections.ObjectModel; using System.Collections.Specialized;class Program {static void …

【java八股文】之Redis基础篇

1、Redis有哪几种基本的数据类型 字符串类型&#xff1a;用于存储文章的访问量Hash&#xff1a;用来存储key-value的数据结构&#xff0c;当单个元素比较小和元素数量比较少的时候 &#xff0c;底层是用ziplist存储。通常可以用来存储一些对象之类的List: 底层采用的quicklist …

2024儿童台灯哪个品牌更护眼推荐?五款知名品牌台灯推荐

只要有了娃&#xff0c;家长的吃穿用度可能不会特别讲究&#xff0c;但总想给孩子好的东西&#xff0c;尤其是关系到他们身心健康的&#xff0c;可以说是一掷千金。特别是眼睛视力方面&#xff0c;特别担心会遗传给孩子&#xff0c;自从他上幼儿园&#xff0c;我就一直在物色一…

WPF 获取父容器控件的宽度

在WPF中&#xff0c;如果你想要获取一个控件的父容器&#xff08;Parent&#xff09;的宽度&#xff0c;你可以通过以下方式访问&#xff1a; double parentWidth this.Parent.ActualWidth;这里的 this 指的是当前控件实例。.Parent 属性返回直接父容器&#xff0c;.ActualWi…

WSL不同版本的Ubuntu更换清华镜像,加速Ubuntu软件下载速度

文章目录 不同版本的Ubuntu使用清华镜像&#xff0c;加速Ubuntu软件下载速度1. 备份源软件配置文件2. 复制镜像源3. 修改软件源配置文件4. 更新软件包列表&#xff0c;升级软件包等内容5. 从仓库中下载其它软件可能存在的问题 不同版本的Ubuntu使用清华镜像&#xff0c;加速Ubu…

鸿蒙Harmony--LocalStorage--页面级UI状态存储详解

走的太急疼的是脚&#xff0c;逼的太紧累的是心&#xff0c;很多时候&#xff0c;慢一点也没关系&#xff0c;多给自己一些耐心和等待&#xff0c;保持热爱&#xff0c;当下即是未来&#xff0c;生活自有安排! 目录 一&#xff0c;定义 二&#xff0c;LocalStorageProp定义 三…

【面试宝典】如何对MySQL进行优化?

一、数据库设计 所有字段都设置默认值。尽可能使用较小的整数类型。尽可能定义字段为NOT NULL,除非该字段需要NULL。尽可能使用固定大小的记录格式,如CHAR,除非变长字段用VARCHAR。二、数据库使用 尽量使用长连接。使用 EXPLAIN 查看复杂SQL执行方式,进行优化。使用 LIMIT …

2024 CKA 题库 | 7、调度 pod 到指定节点

不等更新题库 文章目录 7、调度 pod 到指定节点题目:考点&#xff1a;参考链接:解答:更换 context创建 pod yaml创建 pod 检查 7、调度 pod 到指定节点 题目: 设置配置环境&#xff1a; [candidatenode-1] $ kubectl config use-context k8sTask 按如下要求调度一个 pod&…

Java Web 开发 从入门到实战(课后习题)

第1章 Web 前端基础 1.在以下标记中&#xff0c;用于改置页面标题的是&#xff08;&#xff09;。 A. <title> B. <caption> C. <head> D. <html> 注&#xff1a;caption是表格名称&#xff08;标题&#xff09; 2. 若设计网页的背景图形为bg.png&…

使用Mixtral-offloading在消费级硬件上运行Mixtral-8x7B

Mixtral-8x7B是最好的开放大型语言模型(LLM)之一&#xff0c;但它是一个具有46.7B参数的庞大模型。即使量化为4位&#xff0c;该模型也无法在消费级GPU上完全加载(例如&#xff0c;24 GB VRAM是不够的)。 Mixtral-8x7B是混合专家(MoE)。它由8个专家子网组成&#xff0c;每个子…

Linux--LNMP架构及应用部署

4.2 LNMP架构及应用部署 4.2.1构建LNMP网站平台 为了与Nginx、PHP环境保持一致&#xff0c;仍选择采用源代码编译的方式安装MySQL组件。以5.5.22 版本为例&#xff0c;安装过程如下所述。 &#xff08;1&#xff09;编译安装MySQL。 [rootnode01 ~]# yum -y install ncurses-…

Java中锁的解决方案

前言 在上一篇文章中&#xff0c;介绍了什么是锁&#xff0c;以及锁的使用场景&#xff0c;本文继续给大家继续做深入的介绍&#xff0c;介绍JAVA为我们提供的不同种类的锁。 JAVA为我们提供了种类丰富的锁&#xff0c;每种锁都有不同的特性&#xff0c;锁的使用场景也各不相…

Java 面试题 - 多线程并发篇

线程基础 创建线程有几种方式 继承Thread类 可以创建一个继承自Thread类的子类&#xff0c;并重写其run()方法来定义线程的行为。然后可以通过创建该子类的实例来启动线程。 示例代码&#xff1a; class MyThread extends Thread {public void run() {// 定义线程的行为} …

JUC02同步和锁

同步&锁 相关笔记&#xff1a;www.zgtsky.top 临界区 临界资源&#xff1a;一次仅允许一个进程使用的资源成为临界资源 临界区&#xff1a;访问临界资源的代码块 竞态条件&#xff1a;多个线程在临界区内执行&#xff0c;由于代码的执行序列不同而导致结果无法预测&am…