Java Deadlock in ClassLoaders
I have written two custom class loaders to load code dynamically.
The first one does load code from a 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);
}
}
}
}
The other class loader takes multiple class loaders to allow to access the
classes of the other class loaders. During the initialization of the first
one, I set an instance of this class loader as the parent. To break the
cycle I use the method '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;
}
}
But when I use this class loaders I get most of the time a deadlock. I
have past here the thread dump: http://pastebin.com/6wZKv4Y0
Since the Java ClassLoader blocks in some methods the thread by
synchronizing on $this, I try to synchronizing on the MultiClassLoader
first and then on the JarClassLoader. This should prevent any deadlocks,
when the order of acquiring a lock is the same. But it seems as somewhere
in the native class loading routine a lock on the class loader is
acquired. I came to this conclusion because the thread 'pool-2-thread-8'
is locked on the object '0x00000007b0f7f710'. But in the log I can't see
when this lock is acquired and by which thread.
How can I find out which thread does the synchronizing on the classloader?
No comments:
Post a Comment