Java中atomic包中的原子操作类总结

本文介绍了Java并发编程中atomic包的作用,它提供了高效、线程安全的原子更新基本类型、数组和引用类型的方法。文章详细讲解了CAS操作原理,包括其与synchronized的区别,并分析了CAS可能导致的ABA问题。此外,文章还列举了AtomicInteger、AtomicLong等类的常用方法,展示了如何使用它们进行线程安全的变量更新。

1. 原子操作类介绍

在并发编程中很容易出现并发安全的问题,有一个很简单的例子就是多线程更新变量 i=1,比如多个线程执行 i++操作,就有可能获取不到正确的值,而这个问题,最常用的方法是通过 Synchronized 进行控制来达到线程安全的目的(关于 synchronized 可以看这篇文章)。但是由于 synchronized 是采用的是悲观锁策略,并不是特别高效的一种解决方案。实际上,在 J.U.C 下的 atomic 包提供了一系列的操作简单,性能高效,并能保证线程安全的类去更新基本类型变量,数组元素,引用类型以及更新对象中的字段类型。atomic 包下的这些类都是采用的是乐观锁策略去原子更新数据,在 java 中则是使用 CAS 操作具体实现。

2. 预备知识–CAS 操作

能够弄懂 atomic 包下这些原子操作类的实现原理,就要先明白什么是 CAS 操作。

什么是 CAS?

使用锁时,线程获取锁是一种悲观锁策略,即假设每一次执行临界区代码都会产生冲突,所以当前线程获取到锁的时候同时也会阻塞其他线程获取该锁。而 CAS 操作(又称为无锁操作)是一种乐观锁策略,它假设所有线程访问共享资源的时候不会出现冲突,既然不会出现冲突自然而然就不会阻塞其他线程的操作。因此,线程就不会出现阻塞停顿的状态。那么,如果出现冲突了怎么办?无锁操作是使用 CAS(compare and swap)又叫做比较交换来鉴别线程是否出现冲突,出现冲突就重试当前操作直到没有冲突为止。

CAS 的操作过程

CAS 比较交换的过程可以通俗的理解为 CAS(V,O,N),包含三个值分别为:V 内存地址存放的实际值;O 预期的值(旧值);N 更新的新值。当 V 和 O 相同时,也就是说旧值和内存中实际的值相同表明该值没有被其他线程更改过,即该旧值 O 就是目前来说最新的值了,自然而然可以将新值 N 赋值给 V。反之,V 和 O 不相同,表明该值已经被其他线程改过了则该旧值 O 不是最新版本的值了,所以不能将新值 N 赋给 V,返回 V 即可。当多个线程使用 CAS 操作一个变量是,只有一个线程会成功,并成功更新,其余会失败。失败的线程会重新尝试,当然也可以选择挂起线程

CAS 的实现需要硬件指令集的支撑,在 JDK1.5 后虚拟机才可以使用处理器提供的 CMPXCHG 指令实现。

Synchronized VS CAS

元老级的 Synchronized(未优化前)最主要的问题是:在存在线程竞争的情况下会出现线程阻塞和唤醒锁带来的性能问题,因为这是一种互斥同步(阻塞同步)。而 CAS 并不是武断的间线程挂起,

<think>我们被要求介绍Java中的Locks、Volatile关键字、Unsafe类和原子类Atomic。根据提供的引用,我们可以整合信息如下: 1. **Unsafe类**:引用[1]提到Unsafe是许多JDK核心类的基础,例如java.util.concurrent.atomic中的原子类、java.util.concurrent.locks中的锁实现、java.nio.DirectByteBuffer(直接内存操作)以及java.lang.Class的部分反射功能。Unsafe类提供了一些低级操作,如直接内存访问、线程调度、CAS操作等,但由于其不安全性(如可能绕过Java的安全机制),通常不推荐开发者直接使用。 2. **原子类Atomic**:引用[2]和引用[4]都提到了AtomicInteger等原子类。原子类的核心是使用了CAS(Compare And Swap)机制,配合volatile关键字保证可见性,从而实现了无锁的线程安全操作。例如,AtomicInteger可以解决多线程环境下的自增操作(如number++)的原子性问题,而无需使用synchronized这样的重量级锁。 3. **Volatile关键字**:引用[3]和引用[5]解释了volatile关键字。volatile主要保证变量的可见性(即一个线程修改了volatile变量,其他线程能立即看到最新的值)和防止指令重排序(通过内存屏障)。但是,volatile不能保证原子性(如自增操作不是原子操作,需要借助原子类或锁)。引用[4]也提到volatile不保证原子性,而原子类可以解决这个问题。 4. **Locks**:引用[1]提到java.util.concurrent.locks中的锁实现基于Unsafe类。Lock接口(如ReentrantLock)提供了比synchronized更灵活的锁机制,例如可重入、可中断、公平锁等特性。Lock的实现通常利用了CAS和volatile等机制。 因此,我们可以这样组织回答: - 先分别介绍这四个概念(按照用户提问顺序:Locks, Volatile, Unsafe, Atomic)。 - 然后可以简要说明它们之间的关系(例如,原子类和锁的实现都依赖于Unsafe类和volatile、CAS等机制)。 注意:由于引用提供了部分信息,我们可以适当引用,但要整合成自然的中文段落。 最后,根据指令,我们需要在回答末尾生成相关问题。 我们开始回答: </think>### Java中Locks、Volatile关键字、Unsafe类和原子类Atomic介绍 #### 1. **Locks锁机制** Java的`java.util.concurrent.locks`提供了显式锁实现(如`ReentrantLock`),相比`synchronized`关键字更灵活: - 支持公平锁/非公平锁策略 - 提供`tryLock()`非阻塞获取锁 - 可实现可中断锁(`lockInterruptibly()`) - 基于AQS(AbstractQueuedSynchronizer)实现,底层依赖Unsafe类的CAS操作[^1][^2] #### 2. **Volatile关键字** 核心特性: - **可见性保证**:线程修改volatile变量后会立即刷新主内存,其他线程读取时强制从主内存获取最新值[^3] - **禁止指令重排序**:通过内存屏障防止JVM编译器优化导致的重排序[^3] - **局限性**: - 不保证原子性(如`volatile int i; i++`仍非线程安全)[^5] - 适用场景:单写多读、状态标志等轻量级同步[^4] #### 3. **Unsafe类** 位于`sun.misc.Unsafe`,是JDK内部核心基础设施(用户代码通常无法直接调用): - 提供底层操作能力: - 直接内存分配/释放(`allocateMemory`/`freeMemory`) - CAS原子指令(`compareAndSwapInt`等) - 线程挂起/恢复(`park`/`unpark`) - 是原子类、锁、NIO的`DirectByteBuffer`等实现的基础[^1] #### 4. **原子类Atomic** `java.util.concurrent.atomic`提供原子操作类(如`AtomicInteger`): - **实现原理**: - 组合使用volatile变量 + Unsafe的CAS指令 - 典型操作:`getAndIncrement()`通过循环CAS实现无锁自增[^2] - **优势**: - 解决volatile的原子性问题(如安全实现`i++`)[^4] - 比synchronized更轻量(无上下文切换开销) - 扩展类型:`AtomicReference`(对象引用)、`LongAdder`(高并发计数优化)等 #### 关键关系总结 ```plaintext Unsafe类 ↓ 提供CAS指令 原子类 (AtomicXXX) → 依赖volatile保证可见性 ↓ 替代部分锁场景 Locks框架 → 依赖CAS实现锁状态变更[^1][^2] ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值