Unsafe

大约 1 分钟魔法

Unsafe

学习参考:

sun.misc.Unsafe

1. 通过反射获取Unsafe实例

    private static Unsafe unsafe;

    static {
        try {
            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            unsafe = (Unsafe) theUnsafe.get(null);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

2. Unsafe实例化一个类

    @DisplayName("Unsafe初始化类(只分配内存不调用构造方法)")
    @Test
    public void test_allocateInstance() throws InstantiationException {
        Entity e = (Entity) unsafe.allocateInstance(Entity.class);
        System.out.println(e.getId()); // 0
    }

3. 修改私有属性值

    @DisplayName("修改私有属性的值")
    @Test
    public void test_putXXX() throws NoSuchFieldException {
        Entity entity = new Entity(1);
        System.out.println("原值: " + entity.getId()); // 1

        Field field = Entity.class.getDeclaredField("id");
        long objectFieldOffset = unsafe.objectFieldOffset(field);
        unsafe.putInt(entity, objectFieldOffset, 2);

        System.out.println("修改后: " + entity.getId()); // 2
    }

4. 抛出受检异常

    @DisplayName("正常的受检异常需要在签名中throws,unsafe不需要")
    @Test
    public void test_throwException() {
        unsafe.throwException(new IOException("This is an IOException"));
    }

5. 使用堆外内存

    @DisplayName("使用堆外内存")
    @Test
    public void test_allocateMemory() {
        unsafe.allocateMemory(1024);
        unsafe.freeMemory(1024);
    }

6. CAS

public class Counter {

    private volatile int count;

    private static long offset;

    static {
        try {
            offset = Unsafe0.unsafe.objectFieldOffset(Counter.class.getDeclaredField("count"));
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

    public void incr() {
        int before = count;
        while (!Unsafe0.unsafe.compareAndSwapInt(this, offset, before, before + 1)) {
            before = count;
        }
    }

    public int getCount() {
        return count;
    }
}
    @DisplayName("CAS")
    @Test
    public void test_compareAndSwapInt() throws InterruptedException {
        Counter counter = new Counter();
        ExecutorService pool = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 100; i++) {
            pool.submit(() -> IntStream.range(0, 10000).forEach(j -> counter.incr()));
        }
        pool.shutdown();
        Thread.sleep(1000L);
        System.out.println(counter.getCount()); // 1000000
    }

7. park/unpark