• Unsafe使用


    Unsafe

    Unsafe类是JDK底层类库提供的、基于Java内存模型访问底层的机制,通过该类可以实例化对象、直接操作堆外内存(直接内存)、CAS原子操作等。Java基于AQS实现的同步工具类、并发容器,Netty对堆外内存的操作都基于该类实现。

    获取Unsafe实例

    Unsafe中提供了静态方法getUnsafe可以直接获取到Unsafe对象,但是该方法只允许JDK类库调用,我们平时开发中调用该方法将抛出SecurityException异常。

    当然在开发中,我们可以使用反射获取到该类实例。该类中包含一个自身属性Unsafe theUnsafe,通过反射获取该属性即可获取一个初始化后的Unsafe实例。

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

    常用方法

    /**
     * 实例化一个类
     * @param var1 要实例化类的Class对象
     */
    public native Object allocateInstance(Class<?> var1) throws InstantiationException;
    
    /**
     * 获取一个类中某个属性的位移
     * @param var1 属性的Field
     */
    public native long objectFieldOffset(Field var1);
    
    /**
     * 获取某个实例对象的int属性值
     * @param var1 实例对象
     * @param var2 int属性的offset
     */
    public native int getInt(Object var1, long var2);
    
    /**
     * 修改实例对象的int属性值
     * @param var1 实例对象
     * @param var2 int属性的offset
     * @param var4 修改值
     */
    public native void putInt(Object var1, long var2, int var4);
    
    // 省略boolean、byte、char、short、float、double、long、Object
    
    /**
     * 申请堆外内存
     * @param var1 申请内存大小,单位字节
     * @return 堆外内存的起始地址
     */
    public native long allocateMemory(long var1);
    
    /**
     * 释放堆外内存
     * @param var1 堆外内存的起始地址
     */
    public native void freeMemory(long var1);
    
    /**
     * CAS修改实例对象int属性值
     * @param var1 实例对象
     * @param var2 int属性值
     * @param var4 int属性oldVal
     * @param var5 int属性修改值newVal
     */
    public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
    
    // 省略long、Object
    
    /**
     * 唤醒线程
     * 具体使用可以参考 LockSupport.unpark()
     */
    public native void unpark(Object var1);
    
    /**
     * 阻塞线程
     * 具体使用可以参考 LockSupport.park()
     */
    public native void park(boolean var1, long var2);
    
    
    

    代码实例

    public class User {
        private int age = 20;
    
        public static void main(String[] args) {
            // 构造器创建实例
            User user = new User();
            System.out.println(user);
            // age = 20  表明使用构建器创建实例,会初始化实例属性
            System.out.println("unsafeGetAge : " + user.unsafeGetAge() + " userGetAge : " +  user.getAge());
            user.unsafeSetAge(1);
            System.out.println("unsafeGetAge : " + user.unsafeGetAge() + " userGetAge : " +  user.getAge());
    
            user.setAge(2);
            System.out.println("unsafeGetAge : " + user.unsafeGetAge() + " userGetAge : " +  user.getAge());
    
            // unsafe创建实例
            user = User.getInstance();
            System.out.println(user);
            // age = 0  表明使用Unsafe创建实例,并不会初始化实例属性
            System.out.println("unsafeGetAge : " + user.unsafeGetAge() + " userGetAge : " +  user.getAge());
            user.unsafeSetAge(10);
            System.out.println("unsafeGetAge : " + user.unsafeGetAge() + " userGetAge : " +  user.getAge());
    
            // 每次调用都会创建新的实例
            user = User.getInstance();
            System.out.println(user);
            System.out.println("unsafeGetAge : " + user.unsafeGetAge() + " userGetAge : " +  user.getAge());
            user.unsafeSetAge(100);
            System.out.println("unsafeGetAge : " + user.unsafeGetAge() + " userGetAge : " +  user.getAge());
    
            // cas修改
            user.unsafeCas(100, 150);
            System.out.println("unsafeGetAge : " + user.unsafeGetAge() + " userGetAge : " +  user.getAge());
    
        }
    
        private static Unsafe UNSAFE;
        private static long AGE_OFFSET;
    
        static {
    
            try {
                Field f = Unsafe.class.getDeclaredField("theUnsafe");
                f.setAccessible(true);
                UNSAFE = (Unsafe) f.get(null);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
    
            try {
                AGE_OFFSET = UNSAFE.objectFieldOffset(User.class.getDeclaredField("age"));
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
    
        public static User getInstance() {
            try {
                return (User)UNSAFE.allocateInstance(User.class);
            } catch (InstantiationException e) {
                e.printStackTrace();
                throw new RuntimeException("初始化User实例失败");
            }
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public int unsafeGetAge() {
            return UNSAFE.getInt(this, AGE_OFFSET);
        }
    
        public void unsafeSetAge(int age) {
            UNSAFE.putInt(this, AGE_OFFSET, age);
        }
    
        public void unsafeCas(int expectAge, int newAge) {
            UNSAFE.compareAndSwapInt(this, AGE_OFFSET, expectAge, newAge);
        }
    
        @Override
        public String toString() {
            return "User{" +
                "age=" + age + "," +
                "hashcode=" + this.hashCode() +
                '}';
        }
    }
    
    
  • 相关阅读:
    锁表
    vs2010宏的应用
    Oracle:sqlplus查询出的中文是乱码问题的解决(转)
    linux下查看端口和服务的一些命令
    netsh
    xpshutdown关机命令详解
    linux系统如何察看、修改系统时间
    delphi编程中调用其他执行程序?(转)
    如何修改Oracle用户密码的诀窍(转)
    转:用Delphi实现从Excel数据Update(Insert类似)到Oracle数据库表中
  • 原文地址:https://www.cnblogs.com/QullLee/p/12241044.html
Copyright © 2020-2023  润新知