详解JVM双亲委派机制
前言
Java虚拟机(JVM)是一种能够执行Java字节码的虚拟机,它是Java平台的核心部分之一。在Java平台中,类的加载、验证、解析、初始化等操作都是由JVM来完成的。而JVM在执行这些操作时,会采用一种称为“双亲委派机制”的策略来保证Java程序的安全性和稳定性。下面,我们将详细讲解这种机制的实现原理和作用。
双亲委派机制的定义
双亲委派机制,顾名思义,是指当一个Java类使用其它类时,JVM会首先到父类加载器中查找被使用的类,如果父类加载器找到了该类,则直接返回其引用;如果父类加载器没有找到该类,则将该请求委派给子类加载器进行处理,如果子类加载器仍没有找到,则再将请求委派给父类加载器的父类加载器,依次递归,直到找到类为止,或者一直递归到Bootstrap ClassLoader(启动类加载器),如果最终仍然没有找到该类,则抛出ClassNotFoundException异常。
双亲委派机制的作用
双亲委派机制一方面保证了Java程序的稳定性和安全性,另一方面使得Java类库的重用成为可能。由于类的加载是由父类加载器完成的,因此同一个类在不同的类加载器中只会被加载一次,从而避免了类的重复加载,节省了内存空间。
双亲委派机制的实现原理
双亲委派机制的实现原理可以分为三个步骤:
-
当一个Java类需要被加载时,首先由当前线程的类加载器来查找该类是否已经被加载过了,如果已经加载过了,则直接返回其Class对象,如果没有加载过,则进行下一步。
-
调用父类加载器的loadClass()方法来尝试加载该类,如果父类加载器找到了该类,则直接返回其Class对象,如果父类加载器没有找到,则进行下一步。
-
调用Bootstrap ClassLoader(启动类加载器)的loadClass()方法来尝试加载该类,如果启动类加载器找到了该类,则直接返回其Class对象,如果启动类加载器没有找到该类,则抛出ClassNotFoundException异常。
示例说明
下面我们通过两个示例来说明双亲委派机制的应用和效果:
示例一:自定义ClassLoader
import java.io.IOException;
import java.io.InputStream;
public class MyClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.startsWith("java.")) {
return super.loadClass(name);
}
String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
InputStream is = getClass().getResourceAsStream(fileName);
if (is == null) {
return super.loadClass(name);
}
try {
byte[] bytes = new byte[is.available()];
is.read(bytes);
return defineClass(name, bytes, 0, bytes.length);
} catch (IOException e) {
throw new ClassNotFoundException(name);
}
}
}
MyClassLoader是一个自定义ClassLoader,它会优先使用父类加载器来加载类,如果父类加载器没有加载成功,则再使用自己来加载类。在本例中,如果要加载的类的类名以"java."开头,则直接使用父类加载器来加载;否则,会先尝试从当前类路径中查找该类的字节码文件,如果找不到,则使用父类加载器加载。这样就可以实现Java程序中的隔离和安全。如果在程序中使用MyClassLoader来加载文件,那么所有的类都是在MyClassLoader的范围内加载,从而可以避免Java程序中的不必要干扰。
示例二:单例模式
public class Singleton {
private static Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
Singleton是一个单例模式的实现,它只会创建一个实例并返回。在Java程序中,由于所有的类都是被启动类加载器Bootstrap ClassLoader所加载的,因此可以通过反射来破坏Singleton的单例性。但是,如果采用双亲委派机制,将Singleton的实现放到一个自定义的ClassLoader中,则可以保证Singleton的单例性不被破坏。这是因为,如果要破坏Singleton的单例性,则需要同样的类对象,而由于自定义ClassLoader和启动类加载器是互相独立的,它们不会加载同样的类,从而保证了Singleton的单例性不被破坏。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解jvm双亲委派机制 - Python技术站