Java中原子性和CAS

原子性问题出现的背景

在多线程编程中,当多个线程同时访问和修改同一个共享资源时,可能会导致数据不一致的问题。这种情况下,如果一个操作不是原子性的(即不可分割的),那么在执行过程中可能会被其他线程中断,从而导致数据的不一致性。

例如,考虑一个简单的计数器变量 int count = 0;,多个线程同时对这个变量进行自增操作 count++。这个操作实际上包含三个步骤:

  1. 读取当前值。
  2. 将当前值加1。
  3. 将结果写回内存。

如果这些步骤没有被原子地执行,可能会出现以下情况:

  • 线程A读取 count 的值为0。
  • 线程B也读取 count 的值为0。
  • 线程A将 count 的值加1并写回内存,此时 count 的值为1。
  • 线程B也将 count 的值加1并写回内存,此时 count 的值仍然是1。

因此,最终 count 的值应该是2,但实际上却是1,这就是原子性问题的一个典型例子。

CAS(Compare and Swap)如何解决原子性问题

CAS是一种无锁算法,通过硬件指令来保证原子性。CAS操作包含三个参数:内存位置V、预期值A和新值B。CAS操作的执行过程如下:
1. 比较内存位置V的值是否等于预期值A。
2. 如果相等,则将内存位置V的值设置为新值B。
3. 如果不相等,则不做任何操作。

CAS操作通常由硬件支持,确保了操作的原子性。在Java中,java.util.concurrent.atomic 包提供了一系列基于CAS的原子类,这些类可以用于实现线程安全的操作。

实现原子操作需要面临的问题

  1. ABA问题:在一个CAS操作中,如果内存位置V的值从A变为了B,然后再变回A,CAS操作会认为值没有变化,但实际上可能已经发生了多次变化。为了解决这个问题,可以使用带有版本号的CAS操作,如 AtomicStampedReference
  2. 循环时间长开销大:如果CAS操作失败,通常需要在一个循环中重试,这可能会导致较高的CPU开销。
  3. 只能保证一个共享变量的原子操作:CAS操作只能保证单个变量的原子性,对于多个变量的复合操作,仍然需要使用锁或其他机制来保证原子性。

Java中支持原子操作的CAS类

  1. AtomicInteger:提供了一个原子的整数类,可以用于实现线程安全的整数操作。

    import java.util.concurrent.atomic.AtomicInteger;public class AtomicIntegerExample {private static AtomicInteger count = new AtomicInteger(0);public static void increment() {count.incrementAndGet();}public static void main(String[] args) {for (int i = 0; i < 1000; i++) {new Thread(() -> increment()).start();}// 等待所有线程完成try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Final count: " + count.get());}
    }
    
  2. AtomicLong:提供了一个原子的长整数类,适用于需要更大范围的整数操作。

    import java.util.concurrent.atomic.AtomicLong;public class AtomicLongExample {private static AtomicLong count = new AtomicLong(0);public static void increment() {count.incrementAndGet();}public static void main(String[] args) {for (int i = 0; i < 1000; i++) {new Thread(() -> increment()).start();}// 等待所有线程完成try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Final count: " + count.get());}
    }
    
  3. AtomicBoolean:提供了一个原子的布尔值类,适用于需要线程安全的布尔操作。

    import java.util.concurrent.atomic.AtomicBoolean;public class AtomicBooleanExample {private static AtomicBoolean flag = new AtomicBoolean(false);public static void toggleFlag() {flag.set(!flag.get());}public static void main(String[] args) {for (int i = 0; i < 1000; i++) {new Thread(() -> toggleFlag()).start();}// 等待所有线程完成try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Final flag: " + flag.get());}
    }
    
  4. AtomicReference:提供了一个原子的引用类,适用于需要线程安全的引用类型操作。

    import java.util.concurrent.atomic.AtomicReference;public class AtomicReferenceExample {private static AtomicReference<String> message = new AtomicReference<>("Hello");public static void updateMessage(String newMessage) {message.set(newMessage);}public static void main(String[] args) {for (int i = 0; i < 1000; i++) {new Thread(() -> updateMessage("World")).start();}// 等待所有线程完成try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Final message: " + message.get());}
    }
    
  5. AtomicStampedReference:提供了一个带有版本号的原子引用类,用于解决ABA问题。

    import java.util.concurrent.atomic.AtomicStampedReference;public class AtomicStampedReferenceExample {private static AtomicStampedReference<Integer> value = new AtomicStampedReference<>(0, 0);public static void updateValue(int newValue) {int[] stampHolder = {0};int currentStamp = value.getStamp();while (!value.compareAndSet(value.getReference(), newValue, currentStamp, currentStamp + 1)) {currentStamp = value.getStamp();}}public static void main(String[] args) {for (int i = 0; i < 1000; i++) {new Thread(() -> updateValue(i)).start();}// 等待所有线程完成try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Final value: " + value.getReference());}
    }
    

应用场景

  1. 计数器:在多线程环境中,使用 AtomicIntegerAtomicLong 来实现线程安全的计数器。
  2. 状态标志:使用 AtomicBoolean 来实现线程安全的状态标志,例如表示某个任务是否已完成。
  3. 对象引用:使用 AtomicReference 来实现线程安全的对象引用更新。
  4. 解决ABA问题:使用 AtomicStampedReference 来解决ABA问题,特别是在需要精确控制对象状态变化的情况下。

通过这些原子类,可以在多线程环境中实现高效的、无锁的并发控制,避免了传统锁带来的性能开销和复杂性。

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

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

相关文章

基于Python+Vue开发的商城管理系统,大四期末作业,实习作品

项目简介 该项目是基于PythonVue开发的商城管理系统&#xff08;前后端分离&#xff09;&#xff0c;这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能&#xff0c;同时锻炼他们的项目设计与开发能力。通过学习基于Python的网上商城管…

在 Solana 上实现 SOL 转账及构建支付分配器

与以太坊不同&#xff0c;在以太坊中&#xff0c;钱包通过 msg.value 指定交易的一部分并“推送” ETH 到合约&#xff0c;而 Solana 程序则是从钱包“拉取” Solana。 因此&#xff0c;没有“可支付”函数或“msg.value”这样的概念。 下面我们创建了一个新的 anchor 项目&a…

WebRTC搭建与应用(一)-ICE服务搭建

WebRTC搭建与应用(一) 近期由于项目需要在研究前端WebGL渲染转为云渲染&#xff0c;借此机会对WebRTC、ICE信令协议等有了初步了解&#xff0c;在此记录一下&#xff0c;以防遗忘。 第一章 ICE服务搭建 文章目录 WebRTC搭建与应用(一)前言一、ICE是什么&#xff1f;二、什么…

Linux高性能服务器编程 | 读书笔记 | 12. 多线程编程

12. 多线程编程 注&#xff1a;博客中有书中没有的内容&#xff0c;均是来自 黑马06-线程概念_哔哩哔哩_bilibili 早期Linux不支持线程&#xff0c;直到1996年&#xff0c;Xavier Leroy等人开发出第一个基本符合POSIX标准的线程库LinuxThreads&#xff0c;但LinuxThreads效率…

查看Mysql数据库引擎以及修改引擎为innoDB

目录 打开Mysql命令行 打开Mysql命令行 SHOW ENGINES;innoDB在事务型数据库中应用最多&#xff0c;其主要支持事务安全表&#xff08;ACID&#xff09;&#xff0c;行锁定和外键。 介绍下InnoDB的主要特性&#xff1a; 1、InnoDB给MySQL提供了具有提交、回滚和崩溃恢复能力的事…

Moretl安全日志采集工具

永久免费: 至Gitee下载 使用教程: Moretl使用说明 使用咨询: 用途 定时全量或增量采集工控机,电脑文件或日志. 优势 开箱即用: 解压直接运行.不需额外下载.管理设备: 后台统一管理客户端.无人值守: 客户端自启动,自更新.稳定安全: 架构简单,兼容性好,通过授权控制访问. 架…

密码学——密码学概述、分类、加密技术(山东省大数据职称考试)

大数据分析应用-初级 第一部分 基础知识 一、大数据法律法规、政策文件、相关标准 二、计算机基础知识 三、信息化基础知识 四、密码学 五、大数据安全 六、数据库系统 七、数据仓库. 第二部分 专业知识 一、大数据技术与应用 二、大数据分析模型 三、数据科学 密码学 大数据…

nodejs搭配express网站开发后端接口设计需要注意事项

nodejs搭配express网站开发后端接口设计需要注意事项&#xff01;为了回避一些常见的误区&#xff0c;今天和大家汇总一下&#xff0c;最近我遇到的一些错误信息&#xff0c;虽然都是小问题&#xff0c;但是还是需要分享一下&#xff0c;以免大家再次犯错。 1&#xff1a;第一个…

8_HTML5 SVG (4) --[HTML5 API 学习之旅]

8_HTML5 SVG (4) --[HTML5 API 学习之旅] SVG 文本 HTML5 中的 SVG&#xff08;可缩放矢量图形&#xff09;允许你直接在网页中嵌入图形&#xff0c;并且可以使用 <text> 元素来添加文本到这些图形中。以下是四个带有详细注释的 SVG 文本示例&#xff0c;展示了如何在不…

【中标麒麟服务器操作系统实例分享】java应用DNS解析异常分析及处理

了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer.kylinos.cn 文档中心&#xff1a;https://documentkylinos.cn 情况描述 中标麒麟服务器操作系统V7运行在 ARM虚…

谷歌浏览器的界面调整与设置方法

谷歌浏览器是一款广受欢迎的网络浏览器&#xff0c;其简洁的界面和丰富的扩展功能吸引了大量用户。本文将详细介绍如何调整谷歌浏览器的界面以及一些实用的设置方法&#xff0c;帮助你更好地使用这款浏览器。&#xff08;本文由https://chrome.sungyun.cn/的作者进行编写&#…

05、GC基础知识

JVM程序在跑起来之后&#xff0c;在数据的交互过程中&#xff0c;就会有一些数据是过期不用的&#xff0c;这些数据可以看做是垃圾&#xff0c;JVM中&#xff0c;这些垃圾是不用开发者管的&#xff0c;它自己会有一套垃圾回收系统自动回收这些内存垃圾&#xff0c;以备后面继续…

苍穹外卖-day05redis 缓存的学习

苍穹外卖-day05 课程内容 Redis入门Redis数据类型Redis常用命令在Java中操作Redis店铺营业状态设置 学习目标 了解Redis的作用和安装过程 掌握Redis常用的数据类型 掌握Redis常用命令的使用 能够使用Spring Data Redis相关API操作Redis 能够开发店铺营业状态功能代码 功能实…

Spark-Streaming集成Kafka

Spark Streaming集成Kafka是生产上最多的方式&#xff0c;其中集成Kafka 0.10是较为简单的&#xff0c;即&#xff1a;Kafka分区和Spark分区之间是1:1的对应关系&#xff0c;以及对偏移量和元数据的访问。与高版本的Kafka Consumer API 集成时做了一些调整&#xff0c;下面我们…

启动报错java.lang.NoClassDefFoundError: ch/qos/logback/core/status/WarnStatus

报错信息图片 日志&#xff1a; Exception in thread "Quartz Scheduler [scheduler]" java.lang.NoClassDefFoundError: ch/qos/logback/core/status/WarnStatus先说我自己遇到的问题&#xff0c;我们项目在web设置了自定义的log输出路径&#xff0c;多了一个 / 去…

2025erp系统开源免费进销存系统搭建教程/功能介绍/上线即可运营软件平台源码

系统介绍 基于ThinkPHP与LayUI构建的全方位进销存解决方案 本系统集成了采购、销售、零售、多仓库管理、财务管理等核心功能模块&#xff0c;旨在为企业提供一站式进销存管理体验。借助详尽的报表分析和灵活的设置选项&#xff0c;企业可实现精细化管理&#xff0c;提升运营效…

数据增强的几大方式

1. 随机擦除(Random Erasing) 说明 随机在图像中选取一个矩形区域&#xff0c;将其像素值随机化或设为零&#xff0c;以增加模型对部分缺失信息的鲁棒性。 import numpy as np import cv2def random_erasing(image, sl0.02, sh0.2, r10.3):h, w, _ image.shapearea h * wta…

leecode416.分割等和子集

这道题目看了题解把题目转化为01背包问题才恍然大悟&#xff0c;sum为数组的总和&#xff0c;背包容量为sum/2&#xff0c;价值和背包重量都为nums[i]&#xff0c;由于价值和背包重量都为nums[i]&#xff0c;那么容量为sum/2的背包最多只能获得最大的价值是sum/2&#xff0c;所…

首次下载steam更新速度慢解决方法

下载免费的加速器&#xff0c;在加速器的steam商店加速页面→加速后页面上方的区服选择 &#xff08;香港移动&#xff09;→双箭头→改为登录异常专用→在下部的登录修复进入steam更新 就好了&#xff0c;亲测有效

芯片级IO (Pad) Ring IP Checklist

SoC top顶层数字后端实现都会涉及到IO Ring &#xff08;PAD Ring&#xff09;的设计。这里面包括VDD IO,VDDIO IO, Signal IO, Corner IO&#xff0c;Filler IO&#xff0c;IO power cut cell等等。 数字后端零基础入门系列 | Innovus零基础LAB学习Day2 数字IC后端实现TOP F…