1. 概念介绍
sun.misc.Unsafe 是 Java 中的一个特殊类,它提供了一组低级别的、不安全的操作,这些操作通常是 JVM 内部使用的。由于这些操作非常强大且危险,因此 Unsafe 类被设计为只能在受信任的代码中使用。
2. 主要功能和用途
-  
内存操作:
- 直接内存访问:
Unsafe允许直接操作内存地址,绕过 Java 的内存管理机制。例如,allocateMemory和freeMemory方法可以分配和释放内存。 - 数组操作:
arrayBaseOffset和arrayIndexScale方法可以获取数组的基地址和元素大小,从而实现对数组的直接操作。 
 - 直接内存访问:
 -  
对象操作:
- 对象创建:
allocateInstance方法可以直接创建对象实例,而不调用构造函数。 - 字段访问:
objectFieldOffset方法可以获取对象字段的偏移量,从而实现对字段的直接读写。 
 - 对象创建:
 -  
线程操作:
- 线程挂起和恢复:
park和unpark方法可以挂起和恢复线程。 
 - 线程挂起和恢复:
 -  
CAS(Compare-And-Swap)操作:
- 原子操作:
compareAndSwapInt、compareAndSwapLong等方法提供了原子性的比较和交换操作,这是实现无锁数据结构的基础。 
 - 原子操作:
 -  
内存屏障:
- 内存屏障:
loadFence、storeFence和fullFence方法可以插入内存屏障,控制内存操作的顺序。 
 - 内存屏障:
 
示例代码
以下是一些 Unsafe 类的常见用法示例:
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class UnsafeExample {
    public static void main(String[] args) throws Exception {
        // 获取 Unsafe 实例
        Unsafe unsafe = getUnsafe();
        // 直接分配内存
        long address = unsafe.allocateMemory(1024);
        System.out.println("Allocated memory at address: " + address);
        // 写入和读取内存
        unsafe.putByte(address, (byte) 42);
        byte value = unsafe.getByte(address);
        System.out.println("Read byte from memory: " + value);
        // 释放内存
        unsafe.freeMemory(address);
        // 创建对象实例而不调用构造函数
        ExampleClass obj = (ExampleClass) unsafe.allocateInstance(ExampleClass.class);
        System.out.println("Created instance without calling constructor: " + obj);
        // CAS 操作
        long offset = unsafe.objectFieldOffset(ExampleClass.class.getDeclaredField("value"));
        boolean success = unsafe.compareAndSwapInt(obj, offset, 0, 42);
        System.out.println("CAS operation result: " + success);
        System.out.println("Updated value: " + obj.getValue());
    }
    private static Unsafe getUnsafe() throws Exception {
        Field field = Unsafe.class.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        return (Unsafe) field.get(null);
    }
    static class ExampleClass {
        private int value;
        public ExampleClass() {
            this.value = 10;
        }
        public int getValue() {
            return value;
        }
    }
}
 
其中运行结果如下:
 
	private static Unsafe getUnsafe() throws Exception {
        Field field = Unsafe.class.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        return (Unsafe) field.get(null);
    }
 
其中theUnsafe是unsafe中的属性,目的是为了获取unsage对象来操作。
源码如下
package sun.misc;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
public final class Unsafe {
    private static final Unsafe theUnsafe;
    public static final int INVALID_FIELD_OFFSET = -1;
    public static final int ARRAY_BOOLEAN_BASE_OFFSET;
    ```
 
3. 注意事项
- 安全性:
Unsafe类提供了非常底层的操作,使用不当可能会导致 JVM 崩溃、内存泄漏或其他未定义行为。因此,它通常只应在受信任的代码中使用。 - 兼容性:
Unsafe类是sun.misc包的一部分,这意味着它不是 Java 标准库的一部分,可能在未来的 Java 版本中被移除或更改。 - 性能:虽然 
Unsafe类提供了高性能的操作,但它们通常也更复杂且难以调试。 
总结
sun.misc.Unsafe 类提供了许多强大的底层操作,适用于需要高性能或特殊操作的场景。然而,由于其潜在的危险性和非标准性,使用时应格外小心。
4. 举例说明: AtomicBoolean
4.1 源码如下
public class AtomicBoolean implements java.io.Serializable {
    private static final long serialVersionUID = 4654671469794556979L;
    // setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;
    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicBoolean.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }
    private volatile int value;
    ...
    public final boolean compareAndSet(boolean expect, boolean update) {
        int e = expect ? 1 : 0;
        int u = update ? 1 : 0;
        return unsafe.compareAndSwapInt(this, valueOffset, e, u);
    }
    /**
     * Atomically sets the value to the given updated value
     * if the current value {@code ==} the expected value.
     *
     * @param expect the expected value
     * @param update the new value
     * @return {@code true} if successful. False return indicates that
     * the actual value was not equal to the expected value.
     */
    public boolean weakCompareAndSet(boolean expect, boolean update {
        int e = expect ? 1 : 0;
        int u = update ? 1 : 0;
        return unsafe.compareAndSwapInt(this, valueOffset, e, u);
    }
    
    /**
     * Unconditionally sets to the given value.
     *
     * @param newValue the new value
     */
    public final void set(boolean newValue) {
        value = newValue ? 1 : 0;
    }
    
    /**
     * Eventually sets to the given value.
     *
     * @param newValue the new value
     * @since 1.6
     */
    public final void lazySet(boolean newValue) {
        int v = newValue ? 1 : 0;
        unsafe.putOrderedInt(this, valueOffset, v);
    }
    /**
     * Atomically sets to the given value and returns the previous value.
     *
     * @param newValue the new value
     * @return the previous value
     */
    public final boolean getAndSet(boolean newValue) {
        boolean prev;
        do {
            prev = get();
        } while (!compareAndSet(prev, newValue));
        return prev;
    }
    
 
方法中getAndSet 是原子操作,来设置值。
 说实话weakCompareAndSet和compareAndSet两个方法没看出来有什么区别。
 为了保证原子性,value还是使用volatile 修饰。
volatile 是 Java 中的一个关键字,用于修饰变量。它的主要作用是确保变量的可见性和禁止指令重排序。以下是 volatile 的详细作用和使用场景:
- 可见性(Visibility)
当一个变量被声明为 volatile 时,所有线程都能看到该变量的最新值。具体来说: 
- 写操作:当一个线程对 volatile 变量进行写操作时,该操作会立即刷新到主内存中。
 - 读操作:当一个线程对 volatile 变量进行读操作时,该操作会从主内存中读取最新的值,而不是从线程的本地缓存(如 CPU 缓存)中读取。
 
- 禁止指令重排序(Preventing Instruction Reordering)
volatile 变量的读写操作会被编译器和处理器特殊对待,以确保它们不会被重排序。具体来说: 
- 写操作:在写 volatile 变量之前,所有之前的写操作都会被刷新到主内存中。
 - 读操作:在读 volatile 变量之后,所有之后的读操作都会从主内存中读取最新的值。
 
4.2 使用场景
volatile 通常用于以下场景:
- 状态标志:
当一个变量用于表示某种状态标志(如 boolean 类型的标志)时,可以使用 volatile 来确保所有线程都能看到最新的状态。
例如,一个线程可以设置一个 volatile 的 boolean 变量来通知其他线程某个操作已经完成。 - 单例模式的双重检查锁定(Double-Checked Locking):
在单例模式的实现中,可以使用 volatile 来确保实例的初始化操作不会被重排序,从而避免潜在的线程安全问题。 
4.3 注意事项
- 原子性 
  
- volatile 只能保证变量的可见性和禁止指令重排序,但不能保证复合操作的原子性。例如,volatile 不能替代 synchronized 或 AtomicInteger 等原子类来实现原子操作。
 
 - 性能: 
  
- volatile 的性能开销比普通变量要高,因为它涉及到主内存的读写操作。因此,只有在确实需要确保可见性和禁止重排序时才使用 volatile。
 
 
5. compareAndSwapInt 底层原理
Unsafe 类的 compareAndSwapInt 方法是一个本地方法(native method),它的底层实现依赖于操作系统和硬件平台。具体来说,它通常利用了处理器提供的原子性指令(如 x86 架构上的 CMPXCHG 指令)来实现比较和交换操作。
5.1 底层实现原理
-  
处理器指令:
compareAndSwapInt方法的核心是利用处理器的原子性指令来确保操作的原子性。在 x86 架构上,这个指令通常是CMPXCHG。CMPXCHG指令会比较目标内存位置的值与一个期望值,如果相等,则将新值写入目标内存位置;否则,不进行任何操作。
 -  
内存屏障:
- 为了确保操作的原子性和顺序性,
compareAndSwapInt方法通常会插入内存屏障(memory barrier)。内存屏障可以防止指令重排序,确保在屏障之前的所有内存操作都完成之后,屏障之后的内存操作才能开始。 
 - 为了确保操作的原子性和顺序性,
 -  
操作系统支持:
- 不同的操作系统和硬件平台可能有不同的实现方式。例如,在 Linux 上,JVM 可能会调用内核提供的原子操作函数(如 
__sync_bool_compare_and_swap)。 
 - 不同的操作系统和硬件平台可能有不同的实现方式。例如,在 Linux 上,JVM 可能会调用内核提供的原子操作函数(如 
 
5.2 示例代码
以下是一个简化的伪代码,展示了 compareAndSwapInt 方法的底层实现思路:
// 伪代码,实际实现可能更复杂
bool compareAndSwapInt(Object* obj, long offset, int expected, int newValue) {
    // 获取对象的内存地址
    int* address = (int*)((char*)obj + offset);
    // 使用处理器指令进行比较和交换
    bool success = false;
    __asm__ volatile (
        "lock cmpxchg %4, (%3)\n"
        "sete %0\n"
        : "=q" (success)
        : "a" (expected), "q" (newValue), "r" (address)
        : "memory"
    );
    return success;
}
 
5.3 解释
__asm__ volatile:- 这是 GCC 内联汇编的语法,用于在 C 代码中嵌入汇编指令。
 lock cmpxchg %4, (%3):这是 x86 架构上的CMPXCHG指令,它会锁定总线,确保操作的原子性。sete %0:如果CMPXCHG操作成功(即目标内存位置的值等于期望值),则将success设置为true。
- 内存屏障: 
  
__asm__ volatile中的"memory"约束表示这是一个内存屏障,确保在执行这段汇编代码时,之前的所有内存操作都已完成。
 
5.4 总结
compareAndSwapInt 方法的底层实现依赖于处理器提供的原子性指令(如 CMPXCHG)和内存屏障,以确保操作的原子性和顺序性。不同的操作系统和硬件平台可能有不同的实现方式,但核心思想是利用处理器的原子性指令来实现比较和交换操作。


















