Napisałem dwa niestandardowe programy ładujące klasy, aby dynamicznie ładować kod.Zakleszczenie Java w ClassLoaders
Pierwszy z nich ma kod obciążenia ze słoika:
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);
}
}
}
}
Druga klasa ładowarka ładowarki trwa kilka klas, aby umożliwić dostęp do klasy innych ładowarek klasy. Podczas inicjowania pierwszego ustawiłem instancję tego programu ładującego klasy jako rodzica. Aby przerwać cykl, używam metody "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;
}
}
Ale kiedy używam tych ładowarek, najczęściej dostaję impasu. Mam przeszłość tutaj wysypisko wątku: http://pastebin.com/6wZKv4Y0
ponieważ bloki Java classloader w niektórych metodach wątek synchronizując na $ to staram się synchronizacji na MultiClassLoader a potem na JarClassLoader. Powinno to zapobiec jakimkolwiek zakleszczeniom, gdy kolejność pozyskania zamka jest taka sama. Ale wydaje się, że gdzieś w rodzimej procedurze ładowania klasy jest pobierana blokada programu ładującego klasy. Doszedłem do tego wniosku, ponieważ wątek "pool-2-thread-8" jest zablokowany na obiekcie "0x00000007b0f7f710". Ale w dzienniku nie widzę, kiedy ten zamek został zdobyty i przez który wątek.
Jak mogę się dowiedzieć, który wątek synchronizuje się z programem ładującym klasy?
Edycja: Rozwiązałem go, synchronizując wszystkie ładowniki klasy przed wywołaniem metody loadClass MultiClassLoader.
Dlaczego synchronizacja jest w ładowarce klasy nadrzędnej? Nie widzę żadnego powodu. – Holger
Podczas definicji klasy ClassLoader służy jako blokada (synchronizacja (ta)). Po wywołaniu metody loadClass() w narzędziu MultiClassLoader następuje synchronizacja tej klasy ClassLoader. Oznacza: Są przypadki, gdy rodzic (MultiClassLoader) jest zsynchronizowany przed zsynchronizowaniem JarClassLoader. W takim przypadku możesz wejść w zakleszczenie. Poprzez synchronizację możesz uniknąć tego zakleszczenia. –
Nie widzę, jak dodanie większej synchronizacji powinno być w stanie uniknąć zakleszczenia. Twoje pytanie dowodzi, że ta koncepcja nie działa. Mam jednak nadzieję, że moja odpowiedź pomoże. – Holger