JUC并发编程之原子类

这篇具有很好参考价值的文章主要介绍了JUC并发编程之原子类。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1. 什么是原子操作

1.1 原子类的作用

1.2 原子类的常见操作

原子类的使用注意事项


并发编程是现代计算机应用中不可或缺的一部分,而在并发编程中,处理共享资源的并发访问是一个重要的问题。为了避免多线程访问共享资源时出现竞态条件(Race Condition)等问题,Java提供了一组原子类(Atomic Classes)来支持线程安全的操作。

1. 什么是原子操作

在并发编程中,原子操作是不可被中断的一个或一系列操作,要么全部执行成功,要么全部不执行,不会出现部分执行的情况。原子操作能够保证在多线程环境下,对共享资源的操作不会相互干扰,从而确保数据的一致性和可靠性。

1.1 原子类的作用

Java提供了一组原子类,位于java.util.concurrent.atomic包中,用于在多线程环境下进行原子操作。这些原子类利用底层的硬件支持或自旋锁等机制来实现线程安全的操作,避免了显式地使用synchronized关键字等锁机制,从而提高了并发性能。

原子类的作用主要有以下几点:

  1. 提供线程安全的操作: 原子类提供了一些常见的操作,如读取、更新、比较交换等,这些操作在执行时不会受到其他线程的干扰,从而确保数据的一致性。

  2. 避免竞态条件: 使用原子类可以有效地避免多线程环境下的竞态条件问题,例如多个线程同时对同一个变量进行操作,可能导致不可预测的结果。

  3. 提高性能: 原子类在实现上利用了一些底层的技术,避免了传统锁机制的开销,因此在某些情况下可以提供更好的性能。

1.2 原子类的常见操作

1. AtomicBoolean

AtomicBoolean类提供了原子的布尔值操作,支持原子的设置和获取操作。

AtomicBoolean atomicBoolean = new AtomicBoolean(true);

boolean currentValue = atomicBoolean.get(); // 获取当前值
boolean updatedValue = atomicBoolean.compareAndSet(true, false); // 如果当前值为true,则设置为false

 

2. AtomicInteger 和 AtomicLong

AtomicIntegerAtomicLong分别提供了原子的整数和长整数操作,包括增加、减少、获取等操作。

AtomicInteger atomicInt = new AtomicInteger(0);

int currentValue = atomicInt.get(); // 获取当前值
int newValue = atomicInt.incrementAndGet(); // 增加1并返回新值
int updatedValue = atomicInt.addAndGet(5); // 增加5并返回新值

3. AtomicReference

AtomicReference允许在原子级别上操作引用类型的数据。它提供了getsetcompareAndSet等方法。

AtomicReference<String> atomicRef = new AtomicReference<>("initial value");

String currentValue = atomicRef.get(); // 获取当前值
boolean updated = atomicRef.compareAndSet("initial value", "new value"); // 如果当前值为"initial value",则设置为"new value"

 

4. AtomicStampedReference

AtomicStampedReference是对AtomicReference的扩展,它还包含一个时间戳,用于解决ABA问题(即一个值被修改为另一个值,然后又被修改回原来的值,但是在这之间可能发生了其他的变化)。

AtomicStampedReference<String> atomicStampedRef = new AtomicStampedReference<>("initial value", 0);

int currentStamp = atomicStampedRef.getStamp(); // 获取当前时间戳
String currentValue = atomicStampedRef.getReference(); // 获取当前值
boolean updated = atomicStampedRef.compareAndSet("initial value", "new value", 0, 1); // 如果当前值为"initial value"且时间戳为0,则设置为"new value"和时间戳为1

5. AtomicArray

AtomicArray类允许在原子级别上操作数组元素,提供了针对数组元素的原子更新操作。

AtomicIntegerArray atomicIntArray = new AtomicIntegerArray(5);

int currentValue = atomicIntArray.get(2); // 获取索引为2的元素值
atomicIntArray.set(3, 10); // 设置索引为3的元素值为10
int updatedValue = atomicIntArray.getAndAdd(1, 5); // 增加索引为1的元素值,并返回旧值

6. AtomicReferenceFieldUpdater

AtomicReferenceFieldUpdater是Java中的一个工具类,用于进行原子更新类的引用类型字段的操作。它允许您在不使用锁的情况下对指定的引用字段进行原子操作,类似于AtomicFieldUpdater,但专门用于引用类型的字段。AtomicReferenceFieldUpdater主要用于确保在多线程环境下对引用字段的操作是线程安全的,并且可以提供更好的性能。

AtomicReferenceFieldUpdater适用于以下场景:

  1. 当您需要在不使用锁的情况下对特定类的引用字段进行原子更新时。

  2. 当引用字段的访问修饰符是volatile,以确保多线程之间的可见性。

  3. 当您希望在多个实例之间共享原子更新引用字段的功能,而不是整个对象。

要使用AtomicReferenceFieldUpdater,首先需要创建一个AtomicReferenceFieldUpdater的实例。这可以通过调用AtomicReferenceFieldUpdater.newUpdater(Class<T> tclass, Class<V> vclass, String fieldName)方法来实现,其中:

  • tclass是包含字段的类的Class对象。
  • vclass是字段的引用类型的Class对象。
  • fieldName是要进行原子操作的引用字段的名称。

以下是一个示例代码片段,演示如何创建和使用AtomicReferenceFieldUpdater实例:

public class AtomicReferenceFieldUpdaterExample {
    public static class Student {
        public volatile String name;
    }

    public static void main(String[] args) {
        Student student = new Student();
        AtomicReferenceFieldUpdater<Student, String> updater =
                AtomicReferenceFieldUpdater.newUpdater(Student.class, String.class, "name");

        updater.set(student, "Alice"); // 原子地设置name字段为"Alice"
        String updatedName = updater.get(student); // 原子地获取name字段的值
        System.out.println("Updated Name: " + updatedName);
    }
}

AtomicReferenceFieldUpdater提供了一系列的原子操作方法,用于对指定引用字段进行原子更新。这些方法包括:

  • boolean compareAndSet(T obj, V expect, V update):如果当前值等于expect,则将字段更新为update,返回是否更新成功。

  • V getAndSet(T obj, V newValue):将字段更新为newValue,并返回之前的值。

  • V getAndUpdate(T obj, UnaryOperator<V> updateFunction):使用给定的更新函数更新字段,并返回更新前的值。

  • V updateAndGet(T obj, UnaryOperator<V> updateFunction):使用给定的更新函数更新字段,并返回更新后的值。

  • V getAndAccumulate(T obj, V x, BinaryOperator<V> accumulatorFunction):使用给定的累加函数将字段与x进行累加操作,并返回更新前的值。

  • V accumulateAndGet(T obj, V x, BinaryOperator<V> accumulatorFunction):使用给定的累加函数将字段与x进行累加操作,并返回更新后的值。

7. LongAdder

LongAdder是Java并发包中提供的一种用于高并发场景下对long类型进行累加操作的工具类。与传统的AtomicLong相比,LongAdder在高并发情况下通常能够提供更好的性能,因为它采用了一种分段的方式来减少竞争。LongAdder的引入主要是为了应对高并发累加操作的性能瓶颈,特别是在多核处理器上。

LongAdder在高并发场景下的主要优势在于分段累加,以及对热点数据的分离处理。传统的AtomicLong在高并发情况下可能会因为多线程之间的竞争而导致性能下降,而LongAdder通过将累加操作分成多个段,每个段维护一个计数器,从而减少了竞争。

另外,LongAdder还引入了一种称为“分离器”(Cell)的机制。分离器是计数器的基本单元,每个线程在累加时会选择一个分离器进行操作,这避免了多线程频繁地竞争同一个计数器,从而减少了竞争带来的开销。

要使用LongAdder,只需要简单地创建一个LongAdder的实例即可:

LongAdder longAdder = new LongAdder();

 

LongAdder提供了一些常用的方法来进行累加操作:

  • void add(long x):将指定的值添加到计数器中。

  • void increment():将计数器增加1。

  • void decrement():将计数器减少1。

  • long sum():返回当前计数器的总和。

  • void reset():将计数器重置为0。

  • void addThenReset(long x):将指定的值添加到计数器中,然后将计数器重置为0。

原子类的使用注意事项

  1. 性能考虑: 虽然原子类可以提供一定程度的性能优势,但并不是适用于所有情况。在高并发场景下,考虑使用原子类;而在低并发、性能要求不高的情况下,可能传统的同步机制更加合适。

  2. CAS操作的限制: 原子类的底层实现主要依赖于CAS(Compare-And-Swap)操作,这是一种乐观锁机制。然而,CAS操作可能会在竞争激烈的情况下导致自旋等待,影响性能。

  3. ABA问题: 原子类的CAS操作可能存在ABA问题,即一个值从A变为B,然后又从B变为A,这时CAS操作可能会错误地认为值没有发生变化。可以使用AtomicStampedReference来解决此问题。

  4. 复合操作的原子性: 原子类的单个操作是原子的,但多个操作的组合并不一定是原子的。例如,AtomicIntegerincrementAndGet操作是原子的,但在使用时仍然需要考虑复合操作的原子性。

  5. 适用范围: 原子类适用于简单的原子操作,但并不适用于复杂的业务逻辑。对于复杂的操作,可能需要使用锁等更高级的同步机制来确保线程安全。文章来源地址https://www.toymoban.com/news/detail-641124.html

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

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

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

相关文章

  • 《C++并发编程实战》读书笔记(4):原子变量

    标准原子类型的定义位于头文件 atomic 内。原子操作的关键用途是取代需要互斥的同步方式,但假设原子操作本身也在内部使用了互斥,就很可能无法达到期望的性能提升。有三种方法来判断一个原子类型是否属于无锁数据结构: 所有标准原子类型( std::atomic_flag 除外,因为

    2024年02月10日
    浏览(38)
  • java JUC并发编程 第六章 CAS

    第一章 java JUC并发编程 Future: link 第二章 java JUC并发编程 多线程锁: link 第三章 java JUC并发编程 中断机制: link 第四章 java JUC并发编程 java内存模型JMM: link 第五章 java JUC并发编程 volatile与JMM: link 第六章 java JUC并发编程 CAS: link 第七章 java JUC并发编程 原子操作类增强: link 第八章

    2024年02月10日
    浏览(48)
  • java JUC并发编程 第九章 对象内存布局与对象头

    第一章 java JUC并发编程 Future: link 第二章 java JUC并发编程 多线程锁: link 第三章 java JUC并发编程 中断机制: link 第四章 java JUC并发编程 java内存模型JMM: link 第五章 java JUC并发编程 volatile与JMM: link 第六章 java JUC并发编程 CAS: link 第七章 java JUC并发编程 原子操作类增强: link 第八章

    2024年02月07日
    浏览(44)
  • 【并发编程】JUC并发编程(彻底搞懂JUC)

    如果你对多线程没什么了解,那么从入门模块开始。 如果你已经入门了多线程(知道基础的线程创建、死锁、synchronized、lock等),那么从juc模块开始。 新手学技术、老手学体系,高手学格局。 JUC实际上就是我们对于jdk中java.util .concurrent 工具包的简称 ,其结构如下: 这个包

    2024年02月20日
    浏览(51)
  • 第九章 JUC并发编程

    http://t.csdn.cn/UgzQi 使用 AQS加 Lock 接口实现简单的不可重入锁 早期程序员会自己通过一种同步器去实现另一种相近的同步器,例如用可重入锁去实现信号量,或反之。这显然不够优雅,于是在 JSR166(java 规范提案)中创建了 AQS,提供了这种通用的同步器机制。 AQS 要实现的功能

    2023年04月08日
    浏览(40)
  • JUC并发编程(二)

    JUC并发编程(续) 接上一篇笔记:https://blog.csdn.net/weixin_44780078/article/details/130694996 五、Java内存模型 JMM 即 Java Memory Model,它定义了主存、工作内存抽象概念,底层对应着CPU寄存器、缓存、硬件内存、CPU 指令优化等。 JMM 体现在以下几个方面: 原子性:保证指令不会受到线程

    2024年02月05日
    浏览(93)
  • 【JUC并发编程】

    本笔记内容为狂神说JUC并发编程部分 目录 一、什么是JUC 二、线程和进程 1、概述  2、并发、并行 3、线程有几个状态  4、wait/sleep 区别 三、Lock锁(重点)  四、生产者和消费者问题 五、八锁现象 六、集合类不安全  七、Callable ( 简单 ) 八、常用的辅助类(必会) 1、CountDown

    2024年02月09日
    浏览(40)
  • JUC 高并发编程基础篇

    • 1、什么是 JUC • 2、Lock 接口 • 3、线程间通信 • 4、集合的线程安全 • 5、多线程锁 • 6、Callable 接口 • 7、JUC 三大辅助类: CountDownLatch CyclicBarrier Semaphore • 8、读写锁: ReentrantReadWriteLock • 9、阻塞队列 • 10、ThreadPool 线程池 • 11、Fork/Join 框架 • 12、CompletableFuture 1 什么

    2024年02月07日
    浏览(52)
  • JUC并发编程14 | ThreadLocal

    尚硅谷JUC并发编程(100-111) ThreadLocal是什么? ThreadLocal 提供 线程局部变量 。这些变量与正常的变量有所不同,因为每一个线程在访问ThreadLocal实例的时候(通过其get或set方法)都有自己的、独立初始化的变量副本。ThreadLocal实例通常是类中的私有静态字段,使用它的目的是

    2024年02月04日
    浏览(51)
  • 【JUC并发编程】集合类安全问题

    代码演示 上面代码会报错并发修改异常“java.util.ConcurrentModificationException” 1. 使用Vector类【不推荐】 Vector类的add方法是同步方法,但是效率很低 代码演示 2. 使用Collections工具类 使用 Collections.synchronizedList()方法 将普通的ArrayList类转换为安全的集合类 代码演示 3. 使用CopyOnW

    2024年02月12日
    浏览(44)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包