Java 双亲委派机制
首先得了解一下JVM和ClassLoader
JVM
- 当前主流的有三种JVM:
Sun公司:HotSpot
BEA:JRockit
IBM:J9VM
- 首先了解一下Java程序从编译到执行的整个生命周期:
.java
(经过javac.exe编译成class文件)=> .class
(经过类加载器ClassLoader,具体过程有加载、链接、初始化)=> 可以由JVM解析的Java字节码文件
(垃圾回收)=> 卸载
在程序执行时,JVM中各区的线程占有情况:
线程私有:程序计数器、虚拟机栈、本地方法区
线程共享:堆、方法区、堆外内存
- JVM内存结构
- 主要结构
- 方法区
- 堆区
- 栈区(java程序栈)
- 程序计数器:占用某PC寄存器的线程指向了该线程下一条执行语句的地址
- 本地方法栈
- 与本地方法接口的连接
- 主要结构
由于Java的底层是由C++实现,在Java哲学中,其封装了诸如内存管理、线程管理等底层操作,我们使用navie关键词来
在使用例如线程操作时,线程启动函数start其实是封装了操作系统中的方法 private native void start0();
,此部分依靠OS底层实现,即本地方法接口
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
private native void start0();
类加载器
类加载器:对javac生成的class文件进行加载
如图是new一个对象,new的对象的引用存在java栈上,其数据等信息具体存储在堆区中
加载器的分类,我们可以通过一个演示demo进行查看:
- Bootstrap ClassLoader 启动类加载器
- Extention ClassLoader 标准扩展类加载器
- Application ClassLoader 应用类加载器
public static void main(String[] args) throws Exception {
Class cls = Car.class;
ClassLoader classLoader = cls.getClassLoader();
System.out.println(classLoader);
System.out.println(classLoader.getParent());
System.out.println(classLoader.getParent().getParent());
}
双亲委派机制
当类进行加载时,需要进入到对应的类加载器,否则可能引起安全问题
所以双亲委派机制主要用于解决类错乱加载的问题,总结来说就是优先考虑上层的类加载器:
- 类加载器收到类加载的请求
- 将这个请求向上委托给父类加载器去完成,一直向上委托,知道启动类加载
- 启动加载器检查是否能够加载当前这个类,能加载就结束,使用当前的加载器,否则,抛出异常,适知子加载器进行加载
- 重复步骤3