Java魔法类 & Unsafe 未完结
什么是Unsafe类?
Unsafe封装了很多底层基础的操作,比如:数组操作、对象操作、内存操作、CAS操作、线程(park)操作、栅栏(Fence)操作,JUC包
Unsafe类在JDK 8中归属于sun.misc包下,其他JDK版本包位置会略有不同,不过官方期望在后续删除Unsafe类,不建议我们去用。sun下面都所有包都可能会涉及到C++底层操作。
Unsafe作用
官话作用:可用来直接访问系统内存资源并进行自主管理。
实质作用:绕开JVM的实现更底层功能。Unsafe类在提升Java运行效率,增强Java语言底层操作能力方面起了很大的作用。
基于Unsafe诞生了很多高性能框架
Unsafe可认为是Java中留下的后门,提供了一些低层次操作,如直接内存访问、线程调度等。得益于这些操作,一些高性能框架基于此:比如Netty、Cassandra、Hadoop、Kafka等。
Unsafe源码前要知识
无参构造方法:private Unsafe() {}
Unsafe类的内部常量:private static final Unsafe theUnsafe = new Unsafe();
我们每次获取的就是一个单例对象,我们通过getXXX取得内部私有变量即可。
如何获取Unsafe对象
public static void main(String[] args) {
Unsafe willError = Unsafe.getUnsafe(); // 这是我们常见的获取Unsafe方法。但是他会报错
}
我们看一下报错以及原因
Exception in thread “main” java.lang.SecurityException: Unsafe at sun.misc.Unsafe.getUnsafe(Unsafe.java:90) at com.zanglikun.springdataredisdemo.XX.main(XX.java:16)
@CallerSensitive
public static Unsafe getUnsafe() {
Class<?> caller = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(caller.getClassLoader()))
throw new SecurityException("Unsafe");
return theUnsafe;
}
很明显,上文getUnsafe()方法 if中内容,是判定是否是系统去调用这个方法,如果不是就会跑出SecurityException,所以我们就无法正常创建Unsafe对象了。我们获取一个对象,要么new,要么反射。所以,我们需要反射获取Unsafe对象
public static void main(String[] args) throws NoSuchFieldException {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
System.out.println(unsafe);
}
控制台输出
sun.misc.Unsafe@6ae40994
通过Unsafe类绕过JVM到对象管理机制 实现方法调用。
白话就是:不new,不反射,执行目标类中public的方法!
import sun.misc.Unsafe;
import java.lang.reflect.Field;
class Singleton {
// 注意无参构造方法是private的,也就是说我们无法常规new这个对象!
private Singleton() {
System.out.println("Singleton 无参构造 示例化对象,如果我没打印,就代表我不是常规new 出来的对象");
}
public void printDIY() {
System.out.println("Singleton printDIY");
}
}
public class UserVO {
public static void main(String[] args) throws Exception {
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null); // 获取Unsafe对象
Singleton singleton = (Singleton) unsafe.allocateInstance(Singleton.class); // 获取对象示例
singleton.printDIY(); // 执行对象方法
}
}
Singleton printDIY
进程已结束,退出代码0
案例中没有打印无参构造方法,说明我们通过反射获取的Unsafe,可以绕过常规的类加载机制,在不new的前提,调用目标类的方法。
一个非常牛逼的国外作者关于Unsafe的文章:http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/
- Unsafe API的大部分方法都是native实现,它由105个方法组成,主要包括以下几类:
(1)Info相关。主要返回某些低级别的内存信息:addressSize(), pageSize()
(2)Objects相关。主要提供Object和它的域操纵方法:allocateInstance(),objectFieldOffset()
(3)Class相关。主要提供Class和它的静态域操纵方法:staticFieldOffset(),defineClass(),defineAnonymousClass(),ensureClassInitialized()
(4)Arrays相关。数组操纵方法:arrayBaseOffset(),arrayIndexScale()
(5)Synchronization相关。主要提供低级别同步原语(如基于CPU的CAS(Compare-And-Swap)原语):monitorEnter(),tryMonitorEnter(),monitorExit(),compareAndSwapInt(),putOrderedInt()
(6)Memory相关。直接内存访问方法(绕过JVM堆直接操纵本地内存):allocateMemory(),copyMemory(),freeMemory(),getAddress(),getInt(),putInt()
特殊说明: 以上文章,均是我实际操作,写出来的笔记资料,不会盗用别人文章!烦请各位,请勿直接盗用!转载记得标注来源!
相关文章
- Java多维数组声明格式
- Java进阶(二十三)java中long类型转换为int类型
- java工具类-Java对象转换成Map
- java强制删文件夹_Java 删除文件夹 和 文件 集合
- 学java用什么编译器_学习Java用什么编译软件好
- MySQL字段类型如何转为java_Java JDBC中,MySQL字段类型到JAVA类型的转换
- 编写java判断闰年_Java 判断闰年代码实例
- java 读取字符串文件_Java读取文件为字符串
- java的栈内存和堆内存_Java本地方法栈
- petshop java_petshop.java[通俗易懂]
- java如何遍历数组中的元素_js数组遍历方法
- rtsp 获取视频流 java_Java获取rtsp视频流,实现rtsp流预览功能,并将视频流每帧保存成图片…
- JAVA读取csv文件_java读取csv文件某一列
- 【JAVA冷知识】什么是逆变(contravariant)&协变(covariant)?数组支持协变&逆变吗?泛型呢?
- Java家教系统家教网站家教兼职系统
- Spring Boot | 集成MapStruct实现不同类型Java对象间的自动转换
- HTTP、RPC、UI、SQL自动化封装示例(JAVA)
- java的方法和函数(一)
- java的类和对象(三)
- Java容器(七):TreeMap源码分析详解编程语言
- 解锁Java 与 Oracle 的连接之门(java连接oracle)
- 使用Java操作Redis实现自动数据过期(redisjava过期)
- Redis缓存中Java实现过期策略(redisjava过期)
- 策略设计基于Redis与Java的过期策略(redisjava过期)
- 挑战未来:学习Linux与Java(学linux还是java)
- 时间管理Redis中Java键的过期时间(redisjava过期)
- 使用Java实现MySQL数据恢复操作(java恢复mysql)
- 让Java开发能力在Linux下得到更大发挥(java linux编程)
- Java应用在Linux上乱码的原因及解决方法(java linux乱码)
- Linux与Java结合,打造完美解决方案(linux和java)
- Java中的浮点数分析
- 浅析Java方法传值和传引用问题
- 查看Java所支持的语言及相应的版本信息
- MAC系统如何使用SublimeText2直接编译运行java代码