zoukankan      html  css  js  c++  java
  • Java类加载机制

    1. 双亲委派模型

    JVM内置了三个ClassLoader

    • Bootstrap ClassLoader:负责加载%JAVA_HOME%/lib目录中的class(比方说rt.jar里的class),这个ClassLoader是JVM底层实现的,我们无法直接操作
    • Extension ClassLoader:负责加载%JAVA_HOME%/lib/ext中的所有类库(比方说jfxrt.jar,这个大概是JavaFX的核心库?),这个ClassLoader的实现位于sun.misc.Launcher$ExtClassLoader,我们可以直接使用
    • System ClassLoader:负责加载%CLASSPATH%路径的类库,也就是一般的Java程序本体,以及它所依赖的第三方jar包了。这个ClassLoader的实现位于sun.misc.Launcher$AppClassLoader,我们可以直接使用

    上面的ClassLoader是下面的ClassLoader的祖先。(其实调用ExtClassLoader的getParent方法会返回null,但是依然可以认为Bootstrap ClassLoader是Extension ClassLoader的祖先)

    所谓的双亲委派模型(parent-delegation-model),是指某个ClassLoader在收到loadClass的请求时,先将这个请求转发给父ClassLoader,如果父ClassLoader无法加载此Class,再有当前ClassLoader进行加载。

    请注意,这个加载操作是递归的,也就是说每个loadClass的请求都会经过System ClassLoader -> Extension ClassLoader -> Bootstrap ClassLoader这样的流程。

    ps,其实我觉得这个命名不太好,为啥要叫parent-delegation-model呢,我以前一直以为一个ClassLoader有两个父ClassLoader来着。不如叫ancestor-delegation-model,然后翻译为祖先委派模型比较妥当?

    2. 双亲委派模型的意义

    概括的说:防止同一个Class被加载多次

    如果我们想要加载最基本的java.lang.Object,在双亲委派模型下,不管使用哪个ClassLoader,最终都会追溯到Bootstrap ClassLoader进行加载

    这样就保证了整个JVM中,有且只有一个java.lang.Object

    如果不遵守双亲委派模型, 就有可能出现一个JVM内含有多个不同的ClassLoader加载的java.lang.Object的情况,这会引起混乱。

    3. 双亲委派模型的实现

    参考JDK1.8.0_66的java.lang.ClassLoader的loadClass方法的源码

        protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
        {
            synchronized (getClassLoadingLock(name)) {//禁止多线程同时load同一个Class
                // First, check if the class has already been loaded
                Class<?> c = findLoadedClass(name);//看cache里是否已经存在这个Class了,会调用一个native方法
                if (c == null) {
                    long t0 = System.nanoTime();
                    try {
                        if (parent != null) {
                            c = parent.loadClass(name, false);//调用父ClassLoader的loadClass方法,这里就是双亲委派机制的关键了
                        } else {
                            c = findBootstrapClassOrNull(name);//父ClassLoader为null,那么父ClassLoader肯定是Bootstrap ClasLoader了,调用native方法让Bootstrap ClassLoader来加载这个Class
                        }
                    } catch (ClassNotFoundException e) {
                        // ClassNotFoundException thrown if class not found
                        // from the non-null parent class loader
                    }
    
                    if (c == null) {
                        // If still not found, then invoke findClass in order
                        // to find the class.
                        long t1 = System.nanoTime();
                        c = findClass(name);
    
                        // this is the defining class loader; record the stats
                        sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                        sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                        sun.misc.PerfCounter.getFindClasses().increment();
                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }

    4. 对双亲委派模型的破坏

    双亲委派模型只是一种建议,在某些需要高度灵活性的场景下,我们不必遵守双亲委派模型。

    比方说Tomcat

    参考文献

    关于Java类加载双亲委派机制的思考(附一道面试题)

    深入探究JVM | 类加载器与双亲委派模型

    Java虚拟机类加载机制

  • 相关阅读:
    Oracle中TO_DATE格式
    实现带查询功能的Combox控件
    Combox和DropDownList控件的区别
    C# 获取字符串中的数字
    C# try catch finally 执行
    树形DP codevs 1814 最长链
    codevs 2822 爱在心中
    匈牙利算法 cojs.tk 搭配飞行员
    匈牙利算法 codevs 2776 寻找代表元
    2016-6-19 动态规划,贪心算法练习
  • 原文地址:https://www.cnblogs.com/stevenczp/p/7367737.html
Copyright © 2011-2022 走看看