在JDK1.7之前的JDK1.6 ClassLoader筋粗,是這個(gè)樣子的:
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
}
if (c == null) {
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
可以看到loadClass方法是synchronized
,所以如果調(diào)用了java.lang.ClassLoader
的loadClass方法窗悯,則會(huì)是對(duì)象級(jí)同步調(diào)用。
PS:請(qǐng)問方法的修飾符偷拔,可以被子類繼承么蒋院?
為了提高效率,在JDK1.7后莲绰,ClassLoader進(jìn)行了優(yōu)化欺旧,可以并行加載。
如果想要ClassLoader支持并行的能力蛤签,必須滿足以下條件:
- 目前沒有創(chuàng)建該ClassLoader的實(shí)例辞友。
- 所有該ClassLoader的父類都支持并行加載。
PS:一旦聲明為并行加載顷啼,則不能回退(即改回串行加載)踏枣。
總的來說,就是在該ClassLoader和該ClasssLoader的父類中钙蒙,聲明以下靜態(tài)代碼塊(需要注意靜態(tài)代碼塊的順序茵瀑,不懂得請(qǐng)留言)。
static {
ClassLoader.registerAsParallelCapable();
}
private static class ParallelLoaders {
private ParallelLoaders() {
}
private static final Set<Class<? extends ClassLoader>> loaderTypes =
Collections.newSetFromMap(new WeakHashMap<>());
static {
synchronized (loaderTypes) {
loaderTypes.add(ClassLoader.class);
}
}
static boolean register(Class<? extends ClassLoader> c) {
synchronized (loaderTypes) {
if (loaderTypes.contains(c.getSuperclass())) {
loaderTypes.add(c);
return true;
} else {
return false;
}
}
}
static boolean isRegistered(Class<? extends ClassLoader> c) {
synchronized (loaderTypes) {
return loaderTypes.contains(c);
}
}
}
ClassLoader部分代碼截裙帷:
private final ConcurrentHashMap<String, Object> parallelLockMap;
protected static boolean registerAsParallelCapable() {
Class<? extends ClassLoader> callerClass =
Reflection.getCallerClass().asSubclass(ClassLoader.class);
return ParallelLoaders.register(callerClass);
}
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;
}
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
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) {
}
if (c == null) {
long t1 = System.nanoTime();
c = findClass(name);
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
可以看到马昨,如果注冊(cè)了ClassLoader為并行加載,則loadClass
的時(shí)候扛施,鎖的粒度是className
鸿捧,否則鎖的粒度是ClassLoader實(shí)例本身this
。