我已经编写了两个自定义类加载器来动态加载代码。
第一个类加载器可以从Jar文件中加载代码:
但是当我使用这些类加载器时,大部分时间会出现死锁。我在此处粘贴了线程转储: http://pastebin.com/6wZKv4Y0 由于Java ClassLoader在一些方法中通过对$this进行同步来阻止线程,因此我尝试首先在MultiClassLoader上进行同步,然后在JarClassLoader上进行同步。当获取锁的顺序相同时,这应该可以防止任何死锁。但似乎在本地类加载例程中某个地方会获取类加载器的锁。 我得出这个结论是因为线程'pool-2-thread-8'被锁定在对象'0x00000007b0f7f710'上。但是在日志中,我看不到这个锁是由哪个线程获取的以及何时获取的。
如何找出哪个线程在对类加载器进行同步?
编辑: 我通过在调用MultiClassLoader的loadClass之前对所有类加载器进行同步来解决了这个问题。
第一个类加载器可以从Jar文件中加载代码:
package com.customweb.build.bean.include;
import java.net.URL;
import java.net.URLClassLoader;
import com.customweb.build.process.ILeafClassLoader;
public class JarClassLoader extends URLClassLoader implements ILeafClassLoader {
public JarClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
@Override
public Class<?> findClassWithoutCycles(String name) throws ClassNotFoundException {
Class<?> c = findLoadedClass(name);
if (c != null) {
return c;
}
return findClass(name);
}
@Override
protected Class<?> findClass(String qualifiedClassName) throws ClassNotFoundException {
synchronized (this.getParent()) {
synchronized (this) {
return super.findClass(qualifiedClassName);
}
}
}
@Override
public URL findResourceWithoutCycles(String name) {
return super.findResource(name);
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
synchronized (this.getParent()) {
synchronized (this) {
return super.loadClass(name);
}
}
}
}
另一个类加载器采用多个类加载器来访问其他类加载器的类。在第一个类加载器初始化期间,我将此类加载器的实例设置为父级。为了打破循环,我使用“findClassWithoutCycles”方法。
package com.customweb.build.process;
import java.net.URL;
import java.security.SecureClassLoader;
import java.util.ArrayList;
import java.util.List;
public class MultiClassLoader extends SecureClassLoader {
private final List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
public MultiClassLoader(ClassLoader parent) {
super(parent);
}
public void addClassLoader(ClassLoader loader) {
this.classLoaders.add(loader);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
for (ClassLoader loader : classLoaders) {
try {
if (loader instanceof ILeafClassLoader) {
return ((ILeafClassLoader) loader).findClassWithoutCycles(name);
} else {
return loader.loadClass(name);
}
} catch (ClassNotFoundException e) {
// Ignore it, we try the next class loader.
}
}
throw new ClassNotFoundException(name);
}
@Override
protected URL findResource(String name) {
for (ClassLoader loader : classLoaders) {
URL url = null;
if (loader instanceof ILeafClassLoader) {
url = ((ILeafClassLoader) loader).findResourceWithoutCycles(name);
} else {
url = loader.getResource(name);
}
if (url != null) {
return url;
}
}
return null;
}
}
但是当我使用这些类加载器时,大部分时间会出现死锁。我在此处粘贴了线程转储: http://pastebin.com/6wZKv4Y0 由于Java ClassLoader在一些方法中通过对$this进行同步来阻止线程,因此我尝试首先在MultiClassLoader上进行同步,然后在JarClassLoader上进行同步。当获取锁的顺序相同时,这应该可以防止任何死锁。但似乎在本地类加载例程中某个地方会获取类加载器的锁。 我得出这个结论是因为线程'pool-2-thread-8'被锁定在对象'0x00000007b0f7f710'上。但是在日志中,我看不到这个锁是由哪个线程获取的以及何时获取的。
如何找出哪个线程在对类加载器进行同步?
编辑: 我通过在调用MultiClassLoader的loadClass之前对所有类加载器进行同步来解决了这个问题。