Java并发 - 原子类

这篇具有很好参考价值的文章主要介绍了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,初始值为0
        AtomicInteger atomicInteger = new AtomicInteger(0);
        // 执行CAS操作,尝试将值从0更新为1
        boolean 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);

        // 原子性地将标志值设置为false
        flag.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使用示例文章来源地址https://www.toymoban.com/news/detail-808791.html

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"和版本号1
        stampedReference.compareAndSet("initialValue", "newValue", 0, 1);
        
        System.out.println("Stamped Reference Value: " + stampedReference.getReference());
        System.out.println("Stamped Reference Stamp: " + stampedReference.getStamp());
    }
}

到了这里,关于Java并发 - 原子类的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【java】开发——《并发编程》

    目录 一.jmm 二.并发了什么 1.只有一个核(单核)并发还有没有意义 2.单核,还有什么可见性问题 3.并发和并行 三.volitaile 1.变量的可见性问题 2.原因是什么 3.本次修改的变量直接刷到主内存 4.声明其他内存对于这个地址的缓存无效 四.happens-befo 1.顺序性问题 五.volitaile+cas 1.原

    2024年02月22日
    浏览(50)
  • Java后端开发中Java 8,JVM和JDK的关系

    Java8(也就是Java1.8)是Java编程语言的一个主要版本,正式名称为Java Platform, Standard Edition 8 (Java SE 8)。Java 8在2014年3月发布,引入了许多新特性,如Lambda表达式、新的日期时间API、接口中的默认和静态方法等。Java 8的引入使得Java程序可以更加简洁、易读,同时提高了编程效率。

    2024年04月08日
    浏览(45)
  • JVM执行引擎——为什么Java是半编译半解释语言

            起初设计者的初衷是将字节码文件翻译为机器语言的指令来执行即可,就诞生了解释器。但是采用一行行来解释的 效率比较低 ,JIT编译器会将编译后的机器码做一个缓存的操作,放在方法区的JIT代码缓存中,是否需要启用JIT编译器直接将字节码编译为机器码,则

    2024年02月15日
    浏览(51)
  • Java开发 - 你不知道的JVM优化详解

    代码上的优化达到一定程度,再想提高系统的性能就很难了,这时候,优秀的程序猿往往会从JVM入手来进行系统的优化。但话说回来,JVM方面的优化也是比较危险的,如果单单从测试服务器来优化JVM是没有太大的意义的,不同的服务器即使环境相同,访问流量方面也是不一样

    2024年02月07日
    浏览(42)
  • Java开发环境简介(JDK、JRE、JVM)

    目录 1、Java开发环境 2、JDK和JRE 3、JDK下载和安装 3.1 下载 3.2 安装 3.3 配置path环境变量 JDK8配置方案1:只配置path ⭐JDK8配置方案2:配置JAVA_HOME+path(推荐) path配置小结 JDK17配置方案:自动配置 4、Java核心机制:JVM 补充:Java字节码 JVM的优点 JVM的缺点 JVM的运行过程 5、Java程序

    2024年02月21日
    浏览(45)
  • JAVA后端开发面试基础知识(一)——JVM

    Class loader(类装载) 根据给定的全限定名类名(如: java.lang.Object)来装载class文件到 Runtime data area中的method area。 Execution engine(执行引擎) 执行classes中的指令。 Native Interface(本地接口) 与native libraries交互,是其它编程语言交互的接口。 Runtime data area(运行时数据区域) 这就是我们常说

    2024年03月10日
    浏览(61)
  • Java后端开发面试题——JVM虚拟机篇

    目录 什么是程序计数器? 你能给我详细的介绍Java堆吗? 什么是虚拟机栈 1. 垃圾回收是否涉及栈内存? 2. 栈内存分配越大越好吗? 3. 方法内的局部变量是否线程安全? 4.什么情况下会导致栈内存溢出? 5.堆栈的区别是什么? 能不能解释一下方法区(元空间)? 常量池 运行

    2024年02月09日
    浏览(41)
  • 深入理解JVM虚拟机第二十七篇:详解JVM当中InvokeDynamic字节码指令,Java是动态类型语言么?

     😉😉 学习交流群: ✅✅1:这是孙哥suns给大家的福利! ✨✨ 2:我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料 🥭🥭3:QQ群: 583783824   📚📚  工作微信: BigTreeJava 拉你进微信群,免费领取! 🍎🍎4:本文章内容出自上述:Spring应用课程!💞💞

    2024年02月04日
    浏览(46)
  • 🔥🔥Java开发者的Python快速进修指南:网络编程及并发编程

    今天我们将对网络编程和多线程技术进行讲解,这两者的原理大家都已经了解了,因此我们主要关注的是它们的写法区别。虽然这些区别并不是非常明显,但我们之所以将网络编程和多线程一起讲解,是因为在学习Java的socket知识时,我们通常会将它们结合使用,以实现服务器

    2024年02月05日
    浏览(69)
  • Java项目实战--基于SpringBoot3.0开发仿12306高并发售票系统--(一)前置知识

    本文参考自 Springboot3+微服务实战12306高性能售票系统 - 慕课网 (imooc.com) 本章将介绍仿12306售票系统实战开发的开发环境、项目核心技术和功能、项目模块和架构设计、开发所需前置知识,若想直接开始编写代码实现,请关注作者,看后面的第二章——项目实现 后端: JDK 17

    2024年04月12日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包