开发易忽视的问题:AtomicInteger是如何保证线程安全

AtomicInteger 是 Java 并发包 java.util.concurrent.atomic 中的一个类,它提供了对 int 类型变量的原子操作。通过使用底层的硬件原语(如CAS操作),AtomicInteger 能够保证对其操作的线程安全性,而不需要显式使用锁。

CAS 操作

CAS(Compare-And-Swap)是一种原子操作,它包含三个操作数——内存地址、预期值和新值。CAS 操作会比较内存地址中的当前值与预期值,如果两者相等,则将该位置更新为新值;否则,不进行任何操作。整个过程是不可中断的,因此能够保证线程安全。

底层实现

1. 成员变量和构造方法

 

java

代码解读

复制代码

public class AtomicInteger extends Number implements java.io.Serializable { private static final long serialVersionUID = 6214790243416807050L; // Unsafe 实例,用于执行底层的CAS操作 private static final Unsafe unsafe = Unsafe.getUnsafe(); // value 字段在内存中的偏移量 private static final long valueOffset; // 初始化 value 字段的内存偏移量 static { try { valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } // volatile 修饰的 int 值,确保对该值的修改对所有线程可见 private volatile int value; public AtomicInteger(int initialValue) { value = initialValue; } public AtomicInteger() { } }

这里,我们看到 AtomicInteger 使用了 sun.misc.Unsafe 类来进行低级别的原子操作。此外,value 字段被 volatile 修饰,以确保其修改对所有线程立即可见。

2. 核心方法:compareAndSet

 

java

代码解读

复制代码

public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }

compareAndSet 方法直接调用了 Unsafe 的 compareAndSwapInt 方法,这个方法可以保证在硬件层面上的原子性操作。

3. 常用方法

get 和 set

整理了一份好像面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

需要全套面试笔记【点击此处即可】免费获取

java

代码解读

复制代码

public final int get() { return value; } public final void set(int newValue) { value = newValue; }

这些方法分别用于获取和设置当前值,其中 get 方法确保返回最新的值,而 set 方法则直接将新值赋给 value

incrementAndGet 和 decrementAndGet
 

java

代码解读

复制代码

public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next; } } public final int decrementAndGet() { for (;;) { int current = get(); int next = current - 1; if (compareAndSet(current, next)) return next; } }

这些方法通过循环和 CAS 操作来实现自增和自减功能。如果 compareAndSet 操作失败(说明有其他线程修改了 value),则重新读取当前值并重试,直到成功为止。

addAndGet 和 getAndAdd
 

java

代码解读

复制代码

public final int addAndGet(int delta) { for (;;) { int current = get(); int next = current + delta; if (compareAndSet(current, next)) return next; } } public final int getAndAdd(int delta) { for (;;) { int current = get(); int next = current + delta; if (compareAndSet(current, next)) return current; } }

这两个方法实现了加法操作,并返回相应的结果。addAndGet 返回的是加法操作后的新值,而 getAndAdd 返回的是加法操作前的旧值。

4. Unsafe 类的使用

AtomicInteger 依赖于 Unsafe 类来实现底层的原子操作。Unsafe 类提供了一组硬件级别的操作,可以直接操作内存和对象。以下是 compareAndSwapInt 方法的定义:

 

java

代码解读

复制代码

public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);

这个方法是一个本地方法,通过JNI(Java Native Interface)调用底层的硬件指令来实现原子性操作。

5. compareAndSwapInt 分析

此方法的具体实现是在 JVM 的本地代码中完成的,这通常是用 C 或 C++ 编写的。

底层实现

compareAndSwapInt 的具体实现因 JVM 的实现和运行的平台不同而有所差异。以 OpenJDK 为例,在 HotSpot JVM 中,compareAndSwapInt 的实现可以在以下文件中找到:

  • 对于64位架构:src/hotspot/share/runtime/atomic.cpp
  • 对于32位架构:src/hotspot/os_cpu/linux_x86/atomic_linux_x86.inline.hpp

基于x86架构的CAS操作

以 x86 架构为例,底层硬件指令 CMPXCHG(比较并交换)用于实现 CAS 操作。以下是一个伪代码示例,展示了如何在 C++ 中实现 compareAndSwapInt

 

c++

代码解读

复制代码

inline bool compareAndSwapInt(jobject obj, jlong offset, jint expected, jint x) { jint* addr = (jint*)((char*)obj + offset); // 计算对象字段的真实地址 return __sync_bool_compare_and_swap(addr, expected, x); // 使用 GCC 提供的内置函数 }

在这个伪代码中,__sync_bool_compare_and_swap 是 GCC 提供的内置函数,它生成适当的机器指令来实现 CAS 操作。相应的汇编指令可能类似这样:

 

ini

代码解读

复制代码

mov eax, expected ; 将预期值加载到EAX寄存器中 mov ebx, new_value ; 将新值加载到EBX寄存器中 lock cmpxchg [addr], ebx ; 尝试将EBX的值交换到[addr]位置,如果EAX与[addr]内容相同

汇编级别的细节

以下是一个简化的示例,展示了 x86 汇编中的 CMPXCHG 指令:

 

css

代码解读

复制代码

; 输入: ; EAX: 预期值 ; EBX: 新值 ; [ECX]: 内存地址 lock cmpxchg [ecx], ebx ; 如果 [ecx] == eax,则 [ecx] = ebx,否则 eax = [ecx]

如果内存地址 ecx 中的值与 eax 中的值相等,那么将 ebx 中的值写入 ecx 指向的内存地址;否则,将 ecx 指向的内存地址中的值加载到 eax 中。整个操作在硬件层面上是原子的。

总结

AtomicInteger 通过 Unsafe 类提供的原子性操作实现了线程安全的整数操作。它使用 volatile 保证内存可见性,通过 CAS 操作(如 compareAndSet)实现无锁的线程安全。这使得 AtomicInteger 在高并发环境下比传统的同步机制更高效。

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值