UnSafe

58 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第11天,点击查看活动详情

Unsafe类是在sun.misc包下,不属于Java标准。但是很多Java的基础类库,包括一些被广泛使用的高性能开发库都是基于Unsafe类开发的,比如Netty、Cassandra、Hadoop、Kafka等。Unsafe类在提升Java运行效率,增强Java语言底层操作能力方面起了很大的作用。

Java和C++语言的一个重要区别就是Java中我们无法直接操作一块内存区域,不能像C++中那样可以自己申请内存和释放内存。 Java中的Unsafe类为我们提供了类似C++手动管理内存的能力,同时也有了指针的问题。

首先,Unsafe类是”final”的,不允许继承。且构造函数是private的:

image.png

因此我们无法在外部对Unsafe进行实例化。

获取Unsafe

Unsafe无法实例化,那么怎么获取Unsafe呢?答案就是通过反射来获取Unsafe:

image.png

JUC中大量运用了CAS操作,可以说CAS操作是JUC的基础,因此CAS操作是非常重要的。Unsafe中提供了int,long和Object的CAS操作:

image.png

偏移量相关:

image.png

  • staticFieldOffset方法用于获取静态属性Field在对象中的偏移量,读写静态属性时必须获取其偏移量。
  • objectFieldOffset方法用于获取非静态属性Field在对象实例中的偏移量,读写对象的非静态属性时会用到这个偏移量

类加载

image.png

  • defineClass方法定义一个类,用于动态地创建类。
  • defineAnonymousClass用于动态的创建一个匿名内部类。
  • allocateInstance方法用于创建一个类的实例,但是不会调用这个实例的构造方法,如果这个类还未被初始化,则初始化这个类。
  • shouldBeInitialized方法用于判断是否需要初始化一个类。
  • ensureClassInitialized方法用于保证已经初始化过一个类。
public class UnsafeFooTest {
    private static Unsafe geUnsafe() {

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

    }

    static class Simple {
        private long l = 0;

        public Simple() {
            this.l = 1;
            System.out.println("我被初始化了");
        }

        public long getL() {
            return l;
        }
    }

    public static void main(String[] args) throws Exception {

        Unsafe unsafe = geUnsafe();

        Simple s = (Simple) unsafe.allocateInstance(Simple.class);
        System.out.println(s.getL());
    }
}

输出结果为0,- 可以发现,利用Unsafe获取实例,不会调用构造方法