JVM双亲委派模型

JVM双亲委派模型是一种类加载机制,通过该模型,JVM可以保证Java程序中的类在加载时不会被重复加载,从而保证类的唯一性和程序的安全性。

该模型的核心思想是:当一个类需要被加载时,先把该请求委派给父类加载器去完成,如果父类加载器无法完成加载任务,才由自己去完成加载。这个过程是递归的,一直向上委派,直到到达最顶层的启动类加载器。

这里的“父类加载器”和“子类加载器”指的是类加载器之间的层次关系。在JVM中,类加载器主要分为以下几类:

1 启动类加载器(Bootstrap ClassLoader):这是JVM的内置类加载器,用来加载JVM自身需要的类,例如java.lang.Object等核心类,它是用C++实现的,不是Java类。

2 扩展类加载器(Extension ClassLoader):负责加载Java的扩展类库,默认情况下从jre/lib/ext目录中加载。

3 应用程序类加载器(Application ClassLoader):也称为系统类加载器,负责加载用户自定义的类,它的父类加载器是扩展类加载器。

4 自定义类加载器:用户自定义的类加载器,可以通过继承ClassLoader类来实现。

当一个类需要被加载时,JVM会按照如下的顺序尝试委派给其父类加载器进行加载:

1、应用程序类加载器
2、扩展类加载器
3、启动类加载器

如果所有的父类加载器都无法完成加载任务,才由自己的类加载器去完成加载。这样,就可以保证同一个类只被加载一次,避免出现重复加载的情况,同时也保证了程序的安全性。

举例来说:假设我们有一个自定义的 MyString 类,我们想要在程序中使用。为了加载这个类,虚拟机首先会使用应用程序类加载器(AppClassLoader)来尝试加载这个类。由于应用程序类加载器是双亲委派模型中的最后一个类加载器,它会先请求父类加载器(ExtClassLoader)加载这个类。

父类加载器(ExtClassLoader)会检查自己是否已经加载了 MyString 类。如果没有加载,则它会请求其父类加载器(BootstrapClassLoader)来加载这个类。BootstrapClassLoader 是由 C++ 实现的,因此它无法加载自定义的类。于是,BootstrapClassLoader 返回无法加载 MyString 类的信息。这时,父类加载器(ExtClassLoader)会继续尝试加载这个类。如果 ExtClassLoader 也无法加载这个类,则它会委托给它的子加载器(AppClassLoader)加载这个类。

AppClassLoader 检查它是否已经加载了 MyString 类。如果还没有加载,它将从指定的路径加载该类。如果找到了该类,则 AppClassLoader 将加载它,并将 MyString 类的 Class 对象返回给程序。

这个过程中,父类加载器会检查它的子加载器是否已经加载了这个类,如果已经加载,则返回 Class 对象,如果没有,则继续向上委托,直到 BootstrapClassLoader。如果 BootstrapClassLoader 也无法加载,则返回 Class Not Found 异常。

这个例子展示了双亲委派模型的工作原理。它可以保证类的加载是一种层次结构,每个类只会被加载一次。这避免了重复加载类,并确保了类的唯一性。

双亲委派模型的流程图

当一个 Java 类需要被加载时,JVM 会按照以下步骤进行类的加载操作:

首先,检查该类是否已经被加载过,如果是,则直接返回该类的 Class 对象。

如果该类还没有被加载,则将该请求委托给父类加载器去加载,若父类加载器仍无法加载该类,则继续向上委托,直到委托到最顶层的启动类加载器。

如果父类加载器能够成功加载该类,则直接返回该类的 Class 对象;如果父类加载器无法加载该类,则让子类加载器自行加载该类。

如果所有的父类加载器都无法加载该类,最终会由启动类加载器来尝试加载该类。如果启动类加载器也无法加载该类,则会抛出 ClassNotFoundException 异常。

下面是双亲委派模型的简单流程图:

+------------------------------+
| Bootstrap ClassLoader (C++) |
+------------------------------+
               |
               V
+-----------------------------+
| Extension ClassLoader (Java)|
+-----------------------------+
               |
               V
+-----------------------------+
|   App ClassLoader (Java)    |
+-----------------------------+
               |
               V
+-----------------------------+
|   User-defined ClassLoader  |
+-----------------------------+

其中,Bootstrap ClassLoader 是用 C++ 实现的,负责加载 Java 核心类库(如 rt.jar);Extension ClassLoader 和 App ClassLoader 都是用 Java 实现的,分别负责加载扩展类库和应用程序类库;而 User-defined ClassLoader 则是用户自定义的类加载器,可以根据需要来进行扩展。双亲委派模型中,ClassLoader 在加载类时会优先委托父类加载器来进行加载,直到最终委托给启动类加载器,如果启动类加载器仍无法加载该类,则会抛出 ClassNotFoundException 异常。