Java 原子变量 一次通关

前言

Java中的原子变量是用于实现无锁的线程安全编程的一种机制。它们是java.util.concurrent.atomic包中的一部分,这个包提供了一系列原子类,用于执行原子操作。

主要类型

Java的原子包提供了多种原子类,包括:

  • 基本类型:如AtomicInteger, AtomicLong, AtomicBoolean,它们分别为基本数据类型int, long, boolean提供原子操作。
  • 数组类型:如AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray,它们允许对数组的元素进行原子操作。
  • 复杂类型AtomicReference用于对象引用的原子操作,AtomicStampedReferenceAtomicMarkableReference提供了带有版本号或标记位的对象引用操作,用于解决ABA问题。

使用方式

public class Counter {private AtomicInteger count = new AtomicInteger(0);public void increment() {count.incrementAndGet();}public int getCount() {return count.get();}
}

在这个例子中,increment()方法通过incrementAndGet()原子地增加计数器的值。这意味着即使多个线程同时调用increment()方法,每次调用也都会安全地增加计数器的值,且每个线程看到的count值都是最新的。

原理

Java 中的原子变量之所以能够实现线程安全,主要是基于以下几个核心原理:

原子变量的实现采用了无锁编程技术,这意味着它们不依赖于传统的锁机制(如 synchronized 或 ReentrantLock)来实现线程之间的同步。无锁编程通过一种更加轻量级的方法来处理数据的并发修改,从而减少了线程阻塞和上下文切换的开销。

原子变量中的关键操作(如读取、写入、修改)是通过原子指令来实现的。这些原子指令在底层硬件(如现代的多核处理器)的支持下,保证了在执行过程中的不可中断性。最常用的原子指令包括“比较并交换”(CAS),它包括以下步骤:

  • 读取原始值:首先读取当前的内存位置中的值。
  • 执行比较:检查该值是否仍然等于预期的原值,如果不等于,说明其他线程已经修改了该值,操作失败。
  • 条件更新:如果预期值仍然有效,那么更新为新的值。这整个过程是一个单一的、不可分割的操作。

Java 的原子变量利用了 volatile 变量的内存语义,确保了对这些变量的修改对所有其他线程都是可见的。使用 volatile 变量时,写入变量的操作会确保之前的所有操作对其他线程都是可见的,而从 volatile 变量读取则会确保看到最近一次写入的值。

由于原子变量的操作直接在硬件级别支持,因此它们的执行速度比重量级的锁快得多。这种无锁的特性尤其适合读多写少的场景,可以大幅提高并发性能。

volatile

当一个字段被声明为volatile时,它可以确保所有线程都能看到该字段的最新值。在没有volatile声明的情况下,线程可能从自己的线程栈中缓存变量的值,这意味着当一个线程更新了这个变量时,变化可能对其他线程不可见。

Java内存模型允许编译器和处理器对操作顺序进行重排序,以优化性能。然而,这种重排序不应当干扰单线程程序的执行逻辑。在多线程环境中,为了维护一致性,重排序可能会导致严重问题。当变量被声明为volatile后,任何对该变量的读写操作都将作为内存屏障,防止这类操作与其他内存操作进行重排序。任何写操作之后都会插入一个写屏障,任何读操作之前都会插入一个读屏障。

  • 写屏障:确保在该屏障之前的所有写操作(不仅仅是对volatile变量的写操作)都在写入volatile变量后对其他线程可见。
  • 读屏障:确保在该屏障之后的所有读操作能看到该volatile变量之前的写入。

单个读或写操作对于volatile变量是原子的,某些由多个步骤组成的操作却不能保证在没有外部同步的情况下原子性。

CAS操作实现自旋锁

自旋锁与互斥锁不同,自旋锁的原理是不断尝试占有这把锁,失败就会等待下次再次尝试,互斥锁则是当其他线程尝试占有此锁时将把该线程堵塞,直至锁被释放唤醒

又因为线程被阻塞和唤醒资源消耗较大,

所以自旋锁适用于锁占用很少时间的情况,互斥锁使用于占有锁时间较长的情况。

import java.util.concurrent.atomic.AtomicBoolean;public class SpinLock {private final AtomicBoolean lock = new AtomicBoolean(false);public void lock() {while (!lock.compareAndSet(false, true)) {// 循环直到成功将lock从false设置为true}}public void unlock() {lock.set(false);}
}

 

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

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

相关文章

想自学编程,看编程书有些看不懂,下一步应该怎么办?

不管你从事什么工作,编程都有助于你的职业发展。学习编程将给你自己赋能。我喜欢尝试新想法,时刻都有希望启动的新项目。学会编程后,我就可以坐下来自己实现,而不需要依赖他人。 编程也会提升你在其他方面的技能。因为你熟练掌握…

对SpringBoot配置文件配置项加密原理

参考认识BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor - 知乎 SpringBoot 之 Jasypt 实现yml配置文件加密_-djasypt.encryptor.password-CSDN博客 【springboot】jasypt加密_jasypt.encryptor.password-CSDN博客 实现: 导包: 使…

Gitlab不允许使用ssh拉取代码的解决方案

一、起因 之前一直是用ssh进行代码拉取,后来公司搞网安行动,不允许ssh进行连接拉取代码了 因为我是用shell写了个小型的CI/CD,部署前端项目用于后端联调的,因此在自动部署时,不方便人机交互,所以需要自动填充账密。 …

ZLMediaKit cmake 编译 要点

# 加载自定义模块 list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") project(ZLMediaKit LANGUAGES C CXX) # 使能 C11 set(CMAKE_CXX_STANDARD 11) ############################### SET(CMAKE_SYSTEM_NAME Linux) SET(CMAKE_SYSTEM_PROCESS…

护网2024-攻防对抗解决方案思路

一、护网行动简介 近年来,网络安全已被国家上升为国家安全的战略层面,网络安全同样也被视为维护企业业务持续性的关键。国家在网络安全治理方面不断出台法规与制度,并实施了一些大型项目和计划,如网络安全法、等级保护、网络安全…

【UE C++】 虚幻引擎C++开发需要掌握的C++和U++的基础知识有哪些?

目录 0 引言1 关键的 C 知识2 Unreal Engine 相关知识3 学习建议 🙋‍♂️ 作者:海码007📜 专栏:UE虚幻引擎专栏💥 标题:【UE C】 虚幻引擎C开发需要掌握的C和U的基础知识有哪些?❣️ 寄语&…

【MySQL精通之路】安全(1)-安全指南

任何在连接到Internet的计算机上使用MySQL的人都应该阅读本节,以避免最常见的安全错误。 在讨论安全性时,有必要考虑充分保护整个服务器主机(而不仅仅是MySQL服务器)免受所有类型的适用攻击:窃听、更改、播放和拒绝服…

kafkastream

kafkastream的介绍: Kafka Streams是一个开源的流处理库,用于构建实时数据流应用程序和微服务。它是Apache Kafka项目的一部分,是一种基于事件驱动的流处理解决方案。 Kafka Streams提供了高级别的API,使开发人员能够以简单和声…

什么情况下JVM内存中的一个对象会被垃圾回收?

什么情况下JVM内存中的一个对象会被垃圾回收? 1、什么时候会触发垃圾回收?2、被哪些变量引用的对象是不能回收的?3、Java中对象不同的引用类型4、finalize()方法的作用1、什么时候会触发垃圾回收? 平时我们系统运行创建的对象都是优先分配在新生代里的,如图: 然后如果…

【Oracle】PL SQL 怎么重新编译无效的对象

1.打开PL SQL ,点击图中有红色的 2.点击齿轮按钮即可 from:【Oracle】PL SQL 怎么重新编译无效的对象_plsql编译无效对象的按钮在哪里-CSDN博客

redis查看一个key占用了多少内存

Redis 本身并没有直接提供一个命令来查看一个特定的 key 占用了多少内存。但是,你可以通过一些间接的方法来估算这个值。 以下是一些建议的方法: 使用 DEBUG OBJECT 命令: 虽然这不是一个官方推荐或稳定的命令,但在某些 Redis …

最新php项目加密源码

压缩包里有多少个php就会被加密多少个PHP、php无需安装任何插件。源码全开源 如果上传的压缩包里有子文件夹(子文件夹里的php文件也会被加密),加密后的压缩包需要先修复一下,步骤:打开压缩包 》 工具 》 修复压缩文件…

AIGC 010-CLIP第一个文本和图像对齐的大模型!

AIGC 010-CLIP第一个文本和图像对齐的大模型! 文章目录 0 论文工作1 论文方法2 效果 0 论文工作 不客气的说CLIP和扩散模型的成功让计算式视觉领域几乎所有工作都重新做了一遍。 CLIP(对比语言-图像预训练)论文提出了一种新的对比学习方法&a…

28-ESP32-S3 lwIP 轻量级 TCP/IP 协议栈

ESP32-S3 lwIP 介绍 ESP32-S3 是一款集成了Wi-Fi 和蓝牙功能的微控制器。它的设计初衷是为了方便嵌入式系统的开发。不过你可能会好奇,ESP32-S3 怎么实现与外部网络的通信呢?这里就要提到一个开源的 TCP/IP 协议栈,它叫做lwIP(轻…

博客系统多模块开发

创建工程 创建父工程 删除src目录&#xff0c;在pom.xml添加依赖&#xff1a; <!--统一版本 字符编码--><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.b…

使用 Flask 和 Vue.js 构建 Web 应用

文章目录 入门1. 设置 Flask 后端2. 设置 Vue.js 前端 将 Flask 与 Vue.js 集成1. 配置 Flask 来提供 Vue.js 文件2. 构建 Vue.js 组件3. 运行应用程序 结论 在现代 Web 开发中&#xff0c;创建动态和响应式的应用通常涉及将后端框架如 Flask 与前端库如 Vue.js 结合起来。这种…

职责链设计模式

职责链设计模式&#xff08;Chain of Responsibility Design Pattern&#xff09;是一种行为设计模式&#xff0c;使多个对象都有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合。这些对象被链接成一条链&#xff0c;沿着这条链传递请求&#xff0c;直到有一…

2024年5月20日 (周一) 叶子游戏新闻

报告老板&#xff0c;现在就加班&#xff01;《职场浮生记》抢先体验版现已上线今天由LeiYun Games开发&#xff0c;2P Games发行的《职场浮生记》正式在Steam平台推出抢先体验版。玩家将跟随主角的步伐踏入一个最为真实的职场环境之中&#xff0c;在生活与工作之间找寻平衡&am…

数据库多表查询

多表查询&#xff1a; SELECT *FROM stu_table,class WHERE stu_table.c_idclass.c_id; 多表查询——内连接 查询两张表交集部分。 隐式内连接&#xff1a; #查询学生姓名&#xff0c;和班级名称&#xff0c;隐式调用 SELECT stu_table.s_name,class.c_name FROM stu_table…

Linux管理文本文件002

今天简单和大家分享一些管理文本文件的指令 1、查看文件类型 file 1&#xff09;file /etc/passwd 文本文件 2&#xff09;File /dev/sda 块设备&#xff08;磁盘&#xff09; 3&#xff09;File /dev/tty 字符设备&#xff08;鼠标&#xff09; 4&#xff09;File /usr/…