深入理解并发编程 - sun.misc.Unsafe

本文深入探讨Java中的Unsafe类,介绍如何获取Unsafe实例,以及它如何用于绕过构造函数创建对象、直接修改内存数据和控制类的加载。通过示例代码展示了Unsafe的使用方法,揭示了其强大的底层操作能力。
摘要由CSDN通过智能技术生成

1. 如何获取Unsafe

    Unsafe unsafe = Unsafe.getUnsafe();

通过调用静态方法Unsafe.getUnsafe()就可以获取一个Unsafe的实例,但是在我们自己的类中执行同样的代码却会抛出SecurityException异常。

Exception in thread "main" java.lang.SecurityException: Unsafe

那么为什么会这样呢?其实点进去看源码就知道了。

  @CallerSensitive
    public static Unsafe getUnsafe() {
        Class var0 = Reflection.getCallerClass();
        if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
            throw new SecurityException("Unsafe");
        } else {
            return theUnsafe;
        }
    }

如果调用该方法的类不是被系统类加载器加载的就会抛出异常,通常情况下开发者所开发的Java类都会被应用类加载器进行加载。

在Unsafe类中存在一个Unsafe的实例theUnsafe,该实例是类私有成员,并且在Unsafe类的静态代码块中已经被初始化了,因此我们可以通过反射的方式尝试获取该成员的属性:

        Field field = Unsafe.class.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        Unsafe unsafe = (Unsafe) field.get(null);

2. Unsafe实现的功能

2.1 绕过类构造函数完成对象创建

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        Field field = Unsafe.class.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        Unsafe unsafe = (Unsafe) field.get(null);
        AtomicFieldUpdaterDemo.Alex alex = (AtomicFieldUpdaterDemo.Alex) unsafe.allocateInstance(AtomicFieldUpdaterDemo.Alex.class);
        System.out.println(alex.getSalary()==0);
    }

2.2 直接修改内存数据

public class UnsafeDemo {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        A a = new A();
        System.out.println(a.canAccess(10));
        System.out.println(a.canAccess(1));

        Field field = Unsafe.class.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        Unsafe unsafe = (Unsafe) field.get(null);
        Field accessNo = a.getClass().getDeclaredField("accessNo");
        unsafe.putInt(a,unsafe.objectFieldOffset(accessNo),20);
        System.out.println(a.canAccess(20));
    }

    static class A {
        private int accessNo = 1;

        public boolean canAccess(int num) {
            return this.accessNo == num;
        }
    }
}

2.3 类的加载

   public static void main(String[] args) throws Exception {
        Field field = Unsafe.class.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        Unsafe unsafe = (Unsafe) field.get(null);
        byte[] content = getClassContent();
        Class<?> aClass = unsafe.defineClass(null, content, 0, content.length, null, null);
        Object geta = aClass.getMethod("geta").invoke(aClass.newInstance(), null);
        System.out.println(geta);
    }

    public static byte[] getClassContent() throws Exception {
        File file = new File("C:\\Users\\Administrator\\Documents\\Tencent Files\\1466425779\\FileRecv\\LoadDemo.class");
        try (FileInputStream inputStream = new FileInputStream(file)) {
            byte[] content = new byte[(int) file.length()];
            inputStream.read(content);
            return content;
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值