java 中的Unsafe(转)

本文介绍了Java中的Unsafe类,探讨了其在AtomicInteger中的应用,特别是如何利用Unsafe进行内存位置操作和原子更新。

在阅读AtomicInteger的源码时,看到了这个类:sum.msic.Unsafe,之前从没见过。所以花了点时间google了一下。

 

Unsafe的源码:http://www.docjar.com/html/api/sun/misc/Unsafe.java.html

 

Unsafe源码中的描述如下:

 

 写道
A collection of methods for performing low-level, unsafe operations. Although the class and all methods are public, use of this class is limited because only trusted code can obtain instances of it.

  这个类是用于执行低级别、不安全操作的方法集合。尽管这个类和所有的方法都是公开的(public),但是这个类的使用仍然受限,你无法在自己的java程序中直接使用该类,因为只有授信的代码才能获得该类的实例。

从上面的描述,可以了解到该类是用来执行较低级别的操作的,比如获取某个属性在内存中的位置,不过一般人很少会有这样的需求。在AtomicInteger的源码中相关的代码如下:

Java代码  收藏代码
  1. // setup to use Unsafe.compareAndSwapInt for updates  
  2. private static final Unsafe unsafe = Unsafe.getUnsafe();  

  上面这行代码是获取Unsafe实例的。一般情况下,我们是拿不到该类的实例的,当然jdk库里面是可以随意使用的。

 

 

Java代码  收藏代码
  1. static {  
  2.      try {  
  3.        valueOffset = unsafe.objectFieldOffset  
  4.            (AtomicInteger.class.getDeclaredField("value"));  
  5.      } catch (Exception ex) { throw new Error(ex); }  
  6.    }  

 

  上面这几行代码,是用来获取AtomicInteger实例中的value属性在内存中的位置。这里使用了Unsafe的objectFieldOffset方法。这个方法是一个本地方法, 该方法用来获取一个给定的静态属性的位置。

 

Java代码  收藏代码
  1. public native long objectFieldOffset(Field f);  

 

这里有个疑问,为什么需要获取属性在内存中的位置?通过查看AtomicInteger源码发现,在这样几个地方使用到了这个valueOffset值:

 

Java代码  收藏代码
  1. public final void lazySet(int newValue) {  
  2.         unsafe.putOrderedInt(this, valueOffset, newValue);  
  3.     }  
 
Java代码  收藏代码
  1. public final boolean compareAndSet(int expect, int update) {  
  2.     return unsafe.compareAndSwapInt(this, valueOffset, expect, update);  
  3.     }  

 

 

Java代码  收藏代码
  1. public final boolean weakCompareAndSet(int expect, int update) {  
  2.     return unsafe.compareAndSwapInt(this, valueOffset, expect, update);  
  3.     }  

 

  查找资料后,发现lazySet方法大多用在并发的数据结构中,用于低级别的优化。compareAndSet这个方法多见于并发控制中,简称CAS(Compare And Swap),意思是如果valueOffset位置包含的值与expect值相同,则更新valueOffset位置的值为update,并返回true,否则不更新,返回false。

这里可以举个例子来说明compareAndSet的作用,如支持并发的计数器,在进行计数的时候,首先读取当前的值,假设值为a,对当前值 + 1得到b,但是+1操作完以后,并不能直接修改原值为b,因为在进行+1操作的过程中,可能会有其它线程已经对原值进行了修改,所以在更新之前需要判断原值是不是等于a,如果不等于a,说明有其它线程修改了,需要重新读取原值进行操作,如果等于a,说明在+1的操作过程中,没有其它线程来修改值,我们就可以放心的更新原值了。

 

Unsafe类中还包含有很多其它的方法,如果想使用其中的方法,可以参考这篇文章来获取Unsafe的实例:http://javafans.info/java/corejava/15.html。原理是通过反射机制拿到Unsafe中的一个静态属性theUnsafe ,这个静态属性本身已经初始化了,所以拿到以后可以直接使用。

`sun.misc.Unsafe` 是 Java 中一个非常强大但不推荐直接使用的类,它提供了**底层的、非安全的操作能力**,可以绕过 Java 的一些安全机制(如访问控制、类型检查、内存管理等),直接操作内存、线程、对象等。虽然它不是标准的公共 API,但在 Java 的底层实现中(如 `java.util.concurrent` 包)被广泛使用。 --- ## ✅ `Unsafe` 的主要功能和作用 以下是 `Unsafe` 提供的一些核心功能: ### 1. **直接内存操作(绕过 JVM 堆内存)** - `allocateMemory(long bytes)`:分配一块未初始化的内存。 - `freeMemory(long address)`:释放之前分配的内存。 - `putInt(long address, int x)`、`getInt(long address)`:直接读写指定内存地址的数据。 > 这是实现 `DirectByteBuffer` 的基础,用于高性能的 IO 操作。 ```java long address = unsafe.allocateMemory(4); unsafe.putInt(address, 123456); System.out.println(unsafe.getInt(address)); // 输出 123456 unsafe.freeMemory(address); ``` --- ### 2. **对象字段的偏移量获取与直接访问** - `objectFieldOffset(Field field)`:获取字段在对象中的偏移量。 - `getObject(Object o, long offset)` / `putObject(Object o, long offset, Object x)`:通过偏移量访问或设置字段值。 > 可用于绕过 getter/setter,直接操作对象字段。 ```java class MyClass { private int value; } Field field = MyClass.class.getDeclaredField("value"); long offset = unsafe.objectFieldOffset(field); MyClass obj = new MyClass(); unsafe.putInt(obj, offset, 42); System.out.println(obj.value); // 输出 42 ``` --- ### 3. **CAS 操作(Compare and Swap)** - `compareAndSwapInt(Object o, long offset, int expected, int x)`:原子更新字段值。 > 这是 `AtomicInteger`、`AtomicReference` 等类的底层实现机制。 ```java boolean success = unsafe.compareAndSwapInt(obj, offset, 0, 100); System.out.println(success); // 如果原值为0,则更新为100,返回true ``` --- ### 4. **线程调度** - `park(boolean isAbsolute, long time)` / `unpark(Thread thread)`:挂起和恢复线程。 > `LockSupport` 类的底层实现就是基于 `Unsafe` 的这两个方法。 ```java // 挂起当前线程 unsafe.park(false, 0); // 恢复某个线程 unsafe.unpark(thread); ``` --- ### 5. **类加载与初始化** - `defineClass(String name, byte[] b, int off, int len)`:从字节数组定义类。 - `ensureClassInitialized(Class<?> c)`:确保类被初始化。 > 可用于动态加载类或热部署场景。 --- ### 6. **数组操作** - `arrayBaseOffset(Class<?> arrayClass)`:获取数组第一个元素的偏移量。 - `arrayIndexScale(Class<?> arrayClass)`:获取数组元素之间的步长。 > 用于高效地操作数组内存布局。 --- ## ✅ 获取 `Unsafe` 实例的方法 由于 `Unsafe` 的构造器是私有的,且只能由 JVM 加载的类调用,普通代码不能直接通过 `new Unsafe()` 获取实例。 ```java Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); Unsafe unsafe = (Unsafe) field.get(null); ``` --- ## ⚠️ 使用 `Unsafe` 的风险 - **不安全**:绕过 Java 的安全检查,容易导致内存泄漏、崩溃、不可预测行为。 - **跨平台兼容性差**:不同 JVM 实现可能表现不同。 - **未来可能被移除或限制**:Java 9+ 中模块系统限制了对 `Unsafe` 的访问,未来版本可能进一步限制。 - **不推荐用于业务代码**:除非你是开发底层库(如并发包、NIO 框架、JVM 相关工具)。 --- ## ✅ 实际应用场景 | 场景 | 示例 | |------|------| | 高性能数据结构 | `ConcurrentHashMap`、`AtomicInteger` 等 | | 内存映射 | NIO 的 `DirectByteBuffer` | | 线程控制 | `LockSupport.park()` / `unpark()` | | 动态类加载 | AOP、热部署、JVM 工具等 | --- ## ✅ 总结 `Unsafe` 是 Java 提供的一个底层工具类,它允许你绕过 Java 的安全机制,直接操作内存、对象、线程等,适用于需要极致性能和底层控制的场景。但因其风险高、可移植性差,**不建议普通开发者在业务代码中使用**。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值