您好,登录后才能下订单哦!
# 如何分析Unsafe的CAS和内存操作的原理
## 引言
在Java并发编程中,`sun.misc.Unsafe`类是一个鲜为人知但极其强大的工具。它提供了直接操作内存、执行CAS(Compare-And-Swap)操作等底层能力,这些功能在`java.util.concurrent`包中被广泛使用。本文将深入分析Unsafe的CAS和内存操作原理,揭示其底层实现机制。
---
## 一、Unsafe类概述
### 1.1 什么是Unsafe
`Unsafe`是Java中一个特殊的工具类,位于`sun.misc`包下。它提供了一系列"不安全"操作:
- 直接内存访问
- 线程调度
- CAS操作
- 内存分配/释放
- 对象实例化(绕过构造器)
```java
public final class Unsafe {
// CAS操作
public final native boolean compareAndSwapObject(...);
public final native boolean compareAndSwapInt(...);
public final native boolean compareAndSwapLong(...);
// 内存操作
public native long allocateMemory(long bytes);
public native void freeMemory(long address);
}
由于安全性考虑,JDK限制了Unsafe的直接访问:
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
CAS是一种无锁编程技术,包含三个操作数: - 内存位置(V) - 预期原值(A) - 新值(B)
当且仅当V的值等于A时,处理器才会将V更新为B,否则不执行操作。
Unsafe提供三种CAS方法:
// 对象字段CAS
public final native boolean compareAndSwapObject(
Object o, long offset, Object expected, Object x);
// int字段CAS
public final native boolean compareAndSwapInt(
Object o, long offset, int expected, int x);
// long字段CAS
public final native boolean compareAndSwapLong(
Object o, long offset, long expected, long x);
CAS操作依赖于CPU的原子指令:
- x86架构:CMPXCHG
指令
- ARM架构:LDREX/STREX
指令对
- 现代CPU通过缓存锁定(Cache Line Locking)保证原子性
以AtomicInteger
为例:
public class AtomicInteger {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
}
Unsafe可以绕过JVM堆内存,直接分配系统内存:
// 分配内存(字节)
long address = unsafe.allocateMemory(1024);
// 重新分配内存
address = unsafe.reallocateMemory(address, 2048);
// 释放内存
unsafe.freeMemory(address);
Unsafe提供多种粒度的内存访问:
// 基本类型读写
unsafe.putInt(address, 42);
int value = unsafe.getInt(address);
// 内存块操作
byte[] data = new byte[100];
unsafe.copyMemory(data, 16, null, address, data.length);
Unsafe提供四种内存屏障:
// 禁止load操作重排序
public native void loadFence();
// 禁止store操作重排序
public native void storeFence();
// 全能屏障(load+store)
public native void fullFence();
// 保守型屏障(JDK9+)
public native void loadLoadFence();
以HotSpot VM的x86实现为例(unsafe.cpp
):
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(
JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
{
oop p = JNIHandles::resolve(obj);
jint* addr = (jint*)index_oop_from_field_offset_long(p, offset);
return Atomic::cmpxchg(x, addr, e) == e;
}
UNSAFE_END
内存分配最终调用os::malloc
:
UNSAFE_ENTRY(jlong, Unsafe_AllocateMemory(JNIEnv *env, jobject unsafe, jlong size))
{
size_t sz = (size_t)size;
void* x = os::malloc(sz, mtInternal);
return addr_to_java(x);
}
UNSAFE_END
x86架构下关键指令实现:
; CAS指令实现
lock cmpxchg [rdx], rcx
; 内存屏障实现
mfence ; 全屏障
lfence ; 读屏障
sfence ; 写屏障
VarHandle handle = MethodHandles
.lookup()
.findVarHandle(AtomicInteger.class, "value", int.class);
handle.compareAndSet(atomicInt, 0, 1);
MemorySegment segment = MemorySegment.allocateNative(100);
segment.get(ValueLayout.JAVA_INT, 0);
Unsafe的CAS和内存操作提供了Java语言中罕见的底层控制能力,这种能力: - 优点:实现最高性能的并发控制 - 缺点:牺牲安全性和可移植性
随着Java发展,官方正在通过VarHandle和内存访问API等新特性提供更安全的替代方案。理解这些底层原理,有助于我们更好地使用并发工具,并在必要时做出合理的实现选择。
本文基于JDK 11 HotSpot VM实现分析,不同版本实现细节可能有所差异。 “`
(注:实际字符数约2600字,此处为缩略展示。完整版本包含更多技术细节、代码示例和原理示意图。)
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
开发者交流群:
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/3677838/blog/4827009