vlambda博客
学习文章列表

面试官:回答一下双亲委派模型的好处和它解决的问题


一般情况下我们说了有三种加载器:

  • 最基础:Bootstrap ClassLoader(加载JDK的/lib目录下的类)

  • 次基础:Extension ClassLoader(加载JDK的/lib/ext目录下的类)

  • 普通:Application ClassLoader(程序自己classpath下的类)


双亲委派模型要求如果一个类可以被委派最基础的ClassLoader加载,就不能让高层的ClassLoader加载。


图1:

 



图2:




双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把这个请求委派父类加载器去完成。每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个请求(他的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。



双亲委派模型最大的好处就是让Java类同其类加载器一起具备了一种带优先级的层次关系 如何理解:举个例子,比如我们要加载顶层的Java类——java.lang.Object类,无论我们用哪个类加载器去加载Object类,这个加载请求最终都会委托给Bootstrap ClassLoader,这样就保证了所有加载器加载的Object类都是同一个类。如果没有双亲委派模型,那就乱了套了,完全可以搞出Root::Object和L1::Object这样两个不同的Object类。


源码:java.lang.ClassLoader的loadClass方法中:

 


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; } }



双亲委派模型解决的问题 :

1、每一个类都只会被加载一次,避免了重复加载

2、每一个类都会被尽可能的加载(从引导类加载器往下,每个加载器都可能会根据优先次序尝试加载它)

3、有效避免了某些恶意类的加载(比如自定义了Java。lang.Object类,一般而言在双亲委派模型下会加载系统的Object类而不是自定义的Object类)