ClassLoaderについて

3411 ワード

java.lang public abstract class ClassLoader
classのロードは、委任モデル(delegation model)によって行われます.各クラス・ローダには、関連する親クラス・ローダがあります.クラスをロードすると、class Loaderはそのparent class loaderにクラスをロードするように委任されます.仮想マシン内に構築されたclass Loaderはbootstrap class loaderと呼ばれ、親ローダはありません.
配列class(array classes)はクラスローダによって作成されるのではなく、Javaランタイム(Java runtime)によって必要に応じて自動的に作成されます.
ClassLoaderは、まずlocateでclassのbytecodeを指定し、クラスのbytecodeを実行時のClassに変換します.ランタイムシステムは、bootstrap classes、extension classes、user classesをロードするclass loaderをそれぞれ提供します.CLASSSPATH環境変数は、実行時にシステムがbytecodeをロードする場所を示す.
クラス・ローダは、クラスが要求されると、まずこのクラスが以前にロードされたかどうかを確認します.そうでない場合、親ローダにこのクラスをロードするように要求します.親ローダがこのclassを見つけられなかった場合、クラスローダは自分でこのclassをロードしようとする.
マルチスレッド環境では、カスタムクラスローダで循環委任モデルの問題が発生し、デッドロックが発生する可能性があります.
Class Hierarchy:
  class A extends B
  class C extends D

ClassLoader Delegation Hierarchy:

Custom Classloader CL1:
  directly loads class A 
  delegates to custom ClassLoader CL2 for class B

Custom Classloader CL2:
  directly loads class C
  delegates to custom ClassLoader CL1 for class D

Thread 1:
  Use CL1 to load class A (locks CL1)
    defineClass A triggers
      loadClass B (try to lock CL2)

Thread 2:
  Use CL2 to load class C (locks CL2)
    defineClass C triggers
      loadClass D (try to lock CL1)

ClassをロードするとClassLoaderオブジェクト全体が同期し、デッドロックになる可能性があります
JDK1.7 parallel capable class loaderを導入し、ロックの粒度がclassLoaderから(classLoader+className)に変わり、ロックの粒度を縮小し、この問題を解決しました.
Thread 1:
  Use CL1 to load class A (locks CL1+A)
    defineClass A triggers
      loadClass B (locks CL2+B)

Thread 2:
  Use CL2 to load class C (locks CL2+C)
    defineClass C triggers
      loadClass D (locks CL1+D)

ClassLoaderは初期化時にregisterAsParallelCapable()メソッドを呼び出すことで自分をParallel capable class loaderとして登録し、classを同時ロードすることができ、システム性能の向上に役立つ.デフォルトではClassLoaderはParallel Capableに登録されています
付JDK 1.8クラス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.JDK 8 ClassLoaderソース2.http://docs.oracle.com/javase/7/docs/technotes/guides/lang/cl-mt.html