在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
,所以如果调用了java.lang.ClassLoader
的loadClass方法,则会是对象级同步调用。
PS:请问方法的修饰符,可以被子类继承么?
为了提高效率,在JDK1.7后,ClassLoader进行了优化,可以并行加载。
如果想要ClassLoader支持并行的能力,必须满足以下条件:
- 目前没有创建该ClassLoader的实例。
- 所有该ClassLoader的父类都支持并行加载。
PS:一旦声明为并行加载,则不能回退(即改回串行加载)。
总的来说,就是在该ClassLoader和该ClasssLoader的父类中,声明以下静态代码块(需要注意静态代码块的顺序,不懂得请留言)。
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
。