关于类加载的并发控制锁(ClassLoadingLock)
死锁
在JDK1.7以前,java.lang.ClassLoader的一些核心方法是被synchronized修饰的,比如loadClass,以下摘自JDK6下java.lang.ClassLoader的部分方法:
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {...} private synchronized Class loadClassInternal(String name) throws ClassNotFoundException {...} private synchronized void checkCerts(String name, CodeSource cs) {...} private static synchronized void initSystemClassLoader() {...}
由于方法被synchronized修饰,当BundleA加载PackageB时,要先锁定BundleA类加载器的实例对象,然后将请求委派给BundleB的类加载器处理,但如果这时BundleB也正好想要加载packageA的类,就需要先锁定BundleB类加载器再去请求BundleA的加载器处理,这样两个加载器都在等待对方处理自己的请求,但有各自又都持有己方的锁,就造成了死锁状态。
BundleA和BundleB相互依赖
解决
在JDK1.7之后对这个问题做出了优化,可以以手动注册的方式将类加载标识为具备并行能力,之后在加载类的时候弃用了方法级别synchronized的方式,改为了为每个要加载的class文件(全路径名)都对应一个Object对象锁。加锁的时候如果加载器具备并行能力,那么就不再对类加载器进行加锁,而是找到加载类文件对应的Object锁进行加锁操作。