写点什么

Unsafe-Java 永远的“神”,java 校招面试经验

作者:MySQL神话
  • 2021 年 11 月 28 日
  • 本文字数:3145 字

    阅读完需:约 10 分钟

// 获取数组中第 n 个元素 i = (baseOffset + (scale * n-1))


System.out.println("third element is :" + unsafe.getObject(exampleArray, baseOffset + (scale * 2)));


// 修改数组中第 n 个元素 i = (baseOffset + (scale * n-1))


unsafe.putObject(exampleArray, baseOffset + scale * 2, "柒");


System.out.println("third element is :" + unsafe.getObject(exampleArray, baseOffset + (scale * 2)));


}


public static void main(String[] args) {


OperateArrayExample.operateArrayUseUnsafe();


}


}


输出结果



对象操作




package com.liziba.unsafe;


import com.liziba.unsafe.pojo.User;


import sun.misc.Unsafe;


import java.io.File;


import java.io.FileInputStream;


import java.lang.reflect.Constructor;


import java.lang.reflect.Field;


/**


  • <p>

  • </p>

  • @Author: Liziba

  • @Date: 2021/5/24 20:40


*/


public class OperateObjectExample {


/**


  • 1、public native Object allocateInstance(Class<?> var1); 分配内存

  • 2、public native Class<?> defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6); 方法定义一个类用于动态的创建类

  • @throws Exception


*/


public static void operateObjectUseUnsafe() throws Exception{


Unsafe unsafe = UnsafeFactory.getUnsafe();


// 使用 Unsafe 的 allocateInstance()方法,可以无需使用构造函数的情况下实例化对象


User user = (User) unsafe.allocateInstance(User.class);


user.setId(1);


user.setName("李子捌");


System.out.println(user);


// 返回对象成员属性在内存中相对于对象在内存中地址的偏移量


Field name = User.class.getDeclaredField("name");


long fieldOffset = unsafe.objectFieldOffset(name);


// 使用 Unsafe 的 putXxx()方法,可以直接修改内存地址指向的数据(可以越过权限访问控制符)


unsafe.putObject(user, fieldOffset, "李子柒");


System.out.println(user);


// 使用 Unsafe 在运行时通过.class 文件,创建类


File classFile = new File("E:\workspaceall\liziba-javap5\out\production\liziba-javap5\com\liziba\unsafe\pojo\User.class");


FileInputStream fis = new FileInputStream(classFile);


byte [] classContent = new byte[(int) classFile.length()];


fis.read(classContent);


Class<?> clazz = unsafe.defineClass(null, classContent, 0, classContent.length, null, null);


Constructor<?> constructor = clazz.getDeclaredConstructor(int.class, String.class);


System.out.println(constructor.newInstance(1, "李子玖"));


}


public static void main(String[] args) {


try {


OperateObjectExample.operateObjectUseUnsafe();


} catch (Exception e) {


e.printStackTrace();


}


}


}


输出结果



内存操作




package com.liziba.unsafe;


import sun.misc.Unsafe;


/**


  • <p>

  • </p>

  • @Author: Liziba

  • @Date: 2021/5/24 21:32


*/


public class OperateMemoryExample {


/**


  • 1、public native long allocateMemory(long var1); 分配 var1 字节大小的内存,返回起始地址偏移量

  • 2、public native long reallocateMemory(long var1, long var3); 重新给 var1 起始地址的内存分配长度为 var3 字节的内存,返回新的内存起始地址偏移量

  • 3、public native void freeMemory(long var1); 释放起始地址为 var1 的地址

  • 分配地址的方法还有重分配,都是分配在堆外内存,返回的是一个 long 类型的地址偏移量。这个偏移量在 Java 程序中的每一块内存都是唯一的


*/


public static void operateMemoryUseUnsafe() {


Unsafe unsafe = UnsafeFactory.getUnsafe();


// 申请分配 8byte 的内存


long address = unsafe.allocateMemory(1L);


// 初始化内存填充值


unsafe.putByte(address, (byte)1);


// 测试输出


System.out.println(new StringBuilder().append("address: ").append(address).append(" byte value: ").append(unsafe.getByte(address)));


// 重新分配一个地址


long newAddress = unsafe.reallocateMemory(address, 8L);


unsafe.putLong(newAddress, 8888L);


System.out.println(new StringBuilder().append("address: ").append(newAddress).append(" long value: ").append(unsafe.getLong(newAddress)));


// 释放地址,注意地址可能被其他使用


unsafe.freeMemory(newAddress);


System.out.println(new StringBuilder().append("address: ").append(newAddress).append(" long value: ").append(unsafe.getLong(newAddress)));


}


public static void main(String[] args) {


OperateMemoryExample.operateMemoryUseUnsafe();


}


}


输出结果



CAS 操作




package com.liziba.unsafe;


import com.liziba.unsafe.pojo.User;


import sun.misc.Unsafe;


import java.lang.reflect.Field;


/**


  • <p>

  • </p>

  • @Author: Liziba

  • @Date: 2021/5/24 22:18


*/


public class OperateCASExample {


/**


  • CAS == compare and swap(比较并替换)

  • 当需要改变的值为期望值的时候,就替换为新的值,是原子(不可再分割)操作。Java 中大量的并发框架底层使用到了 CAS 操作。

  • 优势:无锁操作,减少线程切换带来的开销

  • 缺点:CAS 容易在并发的情况下失败从而引发性能问题,也存在 ABA 问题。

  • Unsafe 中提供了三个方法

  • 1、compareAndSwapInt

  • 2、compareAndSwapLong

  • 3、compareAndSwapObject


*/


public static void operateCASUseUnsafe() throws Exception {


User user = new User(1, "李子捌");


System.out.println("pre user value: " + user);


Unsafe unsafe = UnsafeFactory.getUnsafe();


Field id = user.getClass().getDeclaredField("id");


Field name = user.getClass().getDeclaredField("name");


// 获取 ID 字段的内存偏移量


long idFieldOffset = unsafe.objectFieldOffset(id);


// 获取 name 字段的内存偏移量


long nameFieldOffset = unsafe.objectFieldOffset(name);


// 如果 ID 的期望值是 1,则修改为 18 success


unsafe.compareAndSwapInt(user, idFieldOffset, 1, 18);


// 如果 name 的期望值是小荔枝,则修改为李子柒 fail


unsafe.compareAndSwapObject(user, nameFieldOffset, "小荔枝", "李子柒");


// 输出修改的 user 对象


System.out.println("post user value: " + user);


}


public static void main(String[] args) {


try {


OperateCASExample.operateCASUseUnsafe();


} catch (Exception e) {


e.printStackTrace();


}


}


}


输出结果



线程的挂起和恢复




/**


  • 查看 Java 的 java.util.concurrent.locks.LockSupport 源代码可以发现 LockSupport 类

  • 中有各种版本的 pack 方法但是最终都是通过调用 Unsafe.park()方法实现的。


*/


public class LockSupport {


public static void unpark(Thread thread) {


if (thread != null)


UNSAFE.unpark(thread);


}


public static void park(Object blocker) {


Thread t = Thread.currentThread();


setBlocker(t, blocker);


UNSAFE.park(false, 0L);


setBlocker(t, null);


}


public static void parkNanos(Object blocker, long nanos) {


if (nanos > 0) {


Thread t = Thread.currentThread();


setBlocker(t, blocker);


UNSAFE.park(false, nanos);


setBlocker(t, null);


}


}


public static void parkNanos(long nanos) {


if (nanos > 0)


UNSAFE.park(false, nanos);


}


public static void parkUntil(Object blocker, long deadline) {


Thread t = Thread.currentThread();

最后



![](https://upload-images.jianshu.io/upload_i


《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享


mages/22932333-e7f2af0656eab08e?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

用户头像

MySQL神话

关注

还未添加个人签名 2021.11.12 加入

还未添加个人简介

评论

发布
暂无评论
Unsafe-Java永远的“神”,java校招面试经验