支持并行加载,通过对每个类名放置不同的锁来实现。
static { ClassLoader.registerAsParallelCapable(); }
当且仅当父类也是可以并行加载时才会有此属性。最终会落入到此方法,先登记一下。
/** * Registers the given class loader type as parallel capabale. * Returns {@code true} is successfully registered; {@code false} if * loader's super class is not registered. */ static boolean register(Class<? extends ClassLoader> c) { synchronized (loaderTypes) { if (loaderTypes.contains(c.getSuperclass())) { // register the class loader as parallel capable // if and only if all of its super classes are. // Note: given current classloading sequence, if // the immediate super class is parallel capable, // all the super classes higher up must be too. loaderTypes.add(c); return true; } else { return false; } } }
ClassLoader会保存每一个它加载过的类
// The classes loaded by this class loader. The only purpose of this table // is to keep the classes from being GC'ed until the loader is GC'ed. private final Vector<Class<?>> classes = new Vector<>();
// Invoked by the VM to record every loaded class with this loader. void addClass(Class<?> c) { classes.addElement(c); }
上面那个方法。由VM调用,然后把c加入到classes.
protected ClassLoader() { this(checkCreateClassLoader(), getSystemClassLoader()); }
如果没有指定父类加载器,使用系统类加载器(加载classpath的类加载器)。
类加载过程:
1.Invoke findLoadedClass(String) to check if the class has already been loaded. 2.Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead. 3.Invoke the findClass(String) method to find the class.
1.首先自己检查是否已经加载过
2.有父类加载器,调用父类加载器。
3.调用findClass方法去寻找类。如果resolve指定为true,那么,链接这个类。
但是代码有个这样的代码。
if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); }
如果父加载器是null,使用启动类加载器。以下,并行加载器原理
protected Object getClassLoadingLock(String className) { Object lock = this; if (parallelLockMap != null) { Object newLock = new Object(); lock = parallelLockMap.putIfAbsent(className, newLock); if (lock == null) { lock = newLock; } } return lock; }
如果以前注册过并行加载,返回lock不是this而已,这样在loadClass的synchronized的时候锁的对象不同.
此类的findClass方法永远都抛出异常.实现者必须重写这个方法。
protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); }
findResource方法也应该重写了
/** * Finds the resource with the given name. Class loader implementations * should override this method to specify where to find resources. * * @param name * The resource name * * @return A <tt>URL</tt> object for reading the resource, or * <tt>null</tt> if the resource could not be found * * @since 1.2 */ protected URL findResource(String name) { return null; }
findLibrary方法用于寻找库
/** * Returns the absolute path name of a native library. The VM invokes this * method to locate the native libraries that belong to classes loaded with * this class loader. If this method returns <tt>null</tt>, the VM * searches the library along the path specified as the * "<tt>java.library.path</tt>" property. * * @param libname * The library name * * @return The absolute path of the native library * * @see System#loadLibrary(String) * @see System#mapLibraryName(String) * * @since 1.2 */ protected String findLibrary(String libname) { return null; }
返回本地库的绝对路径,VM调用此方法获取属于此ClassLoader的本地库,如果方法返回null,VM在 java.library.path 属性指定的路径中搜索本地库。
usr_paths = initializePath("java.library.path"); sys_paths = initializePath("sun.boot.library.path");