在JDK1.7之前的JDK1.6 ClassLoader,是這個樣子的:
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方法,則會是對象級同步調(diào)用。
PS:請問方法的修飾符,可以被子類繼承么?
為了提高效率,在JDK1.7后,ClassLoader進行了優(yōu)化,可以并行加載。
如果想要ClassLoader支持并行的能力,必須滿足以下條件:
- 目前沒有創(chuàng)建該ClassLoader的實例。
- 所有該ClassLoader的父類都支持并行加載。
PS:一旦聲明為并行加載,則不能回退(即改回串行加載)。
總的來說,就是在該ClassLoader和該ClasssLoader的父類中,聲明以下靜態(tài)代碼塊(需要注意靜態(tài)代碼塊的順序,不懂得請留言)。
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;
}
}
可以看到,如果注冊了ClassLoader為并行加載,則loadClass
的時候,鎖的粒度是className
,否則鎖的粒度是ClassLoader實例本身this
。