zoukankan      html  css  js  c++  java
  • 双亲委派模型


    title: 双亲委派模型
    date: 2018-10-24 15:05:54
    tags:
    categories:

    双亲委派模型

    本来应该是jvm类加载机制的内容,但这个太重要了,我就单独写了一篇。jvm虚拟机有一个重要的判断(之一)两个类是否相等的依据,就是是否是同一个类加载器加载的类,首先要保证同一个类加载器加载,那么命名空间相等才有意义。

    加载器类型

    从java虚拟机的角度来说,有两种类加载器,一种是启动类加载器,另外就是其他类加载器。前者是由C++实现的,属于java虚拟机的一部分,后者使用Java语言实现的,并且继承自java.lang.ClassLoader。
    从java开发者来说则可以细分成三类:

    1. 启动类加载器(Bootstrap ClassLoader),这个就是上面说的启动类加载器,他负责加载<JAVA_HOME>lib目录中的类,还有-Xbootclasspath所指定路径中的,并且是虚拟机识别的类库。
    2. 扩展类加载器(Extension ClassLoader),这个加载器负责加载<JAVA_HOME>libext目录中的类,或者被java.ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用这个类加载器。
    3. 应用程序类加载器(Application ClassLoader),这个类加载器负责加载用户类路径(ClassPath)上所制定的类库,开发者也可以直接使用这个类加载器。

    双亲委派模型

    双亲委派模型就是按照顺序,以此使用这三种类加载器加载类,加载顺序如图所示。

    双亲委派模型
    ClassLoader中双亲委派模型源码实现:

    protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
    {
    synchronized (getClassLoadingLock(name)) {
    // First, check if the class has already been loaded
    Class<?> c = findLoadedClass(name);
    if (c == null) {
    long t0 = System.nanoTime();
    try {
    if (parent != null) {
    c = parent.loadClass(name, false);
    } else {
    c = findBootstrapClassOrNull(name);
    }
    } 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;
    }
    }  
    

    我们在这里简单分析一下远吗,首先我们要判断这个类是否加载过,如果没有加载,则对这个类进行加载。
    加载是先调用父类加载器去加载(不断调用,不知道这里算不算递归??),如果父类加载器不存在,则被认为是Bootstrap加载器,这时候就直接使用这个类加载器进行加载,如果加载失败,就抛出异常。
    介绍完了双亲委派模型,我们要知道为什么要使用这种方式去加载类。

    1. 防止各个类使用不同的类加载器去加载,这样就会导致同一个如果在不同的地方被不同的类加载器加载后,结果会不一样。如果使用双亲委派模型,就能保证不论何时何地加载这个类,都是同样的结果。
    2. 保证类只加载一次,实际上与上面这条也有关联,因为从源码可以看到,在加载类之前要判断是否被加载过,因为加载机制是双亲委派模型,所以保证如果被加载一次,那么必然不会再被加载。
      我想到的原因就这些,如果还有原因欢迎补充。
  • 相关阅读:
    桃花扇
    望故乡
    Unity资源加载方式总结
    [Spark]-RDD详解之变量&操作
    [Spark]-RDD之创建
    [Spark]-RDD初识
    [Spark]-编译(2.3.1)&部署(YARN-Cluster)
    [Spark]-背景
    [Hive]-常规优化以及执行计划解析
    [转载]线上应用故障排查之一:高memory占用
  • 原文地址:https://www.cnblogs.com/zhoujiayong/p/10144606.html
Copyright © 2011-2022 走看看