Kodu dinamik olarak yüklemek için iki özel sınıf yükleyici yazdım.Sınıfı Yükleyicilerde Java Kilitlenme Kodu
birincisi kavanoz yük kodu yapar:
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);
}
}
}
}
diğer sınıfı yükleyici, diğer sınıf yükleyiciler sınıfları erişimine izin vermek için çok sayıda sınıf yükleyiciler alır. İlkinin başlatılması sırasında, bu sınıf yükleyicinin bir örneğini üst öğe olarak ayarladım. Döngüyü kırmak için 'findClassWithoutCycles' yöntemini kullanıyorum.
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;
}
}
Ancak bu sınıf yükleyicileri kullandığımda çoğu zaman bir kilitlenme oluyor. Burada iplik dökümü geçmiş vardır: $ bu konuda senkronize ederek iplik, ilk ve ardından JarClassLoader üzerinde MultiClassLoader üzerinde senkronize deneyin bazı yöntemlerde Java ClassLoader blokları yana http://pastebin.com/6wZKv4Y0
. Bu, bir kilit elde etme sırasının aynı olduğu durumlarda herhangi bir kilitlenmeyi önlemelidir. Ancak, yerel sınıf yükleme rutininde, sınıf yükleyicinin üzerinde bir kilit elde edildiği görülüyor. Bu sonuca vardım çünkü 'havuz-2-thread-8' parçacığı '0x00000007b0f7f710' nesnesinde kilitlendi. Fakat günlüğünde bu kilidin ne zaman elde edildiğini ve hangi iş parçacığı ile göremiyorum.
Sınıf yükleyicide hangi iş parçacığının eşitleme yaptığını nasıl öğrenebilirim?
Düzenleme: Tüm sınıf yükleyicileri, MultiClassLoader öğesinin loadClass'ını çağırmadan önce senkronize ederek çözdüm.
Neden üst sınıf yükleyicide eşitleme yapıyorsunuz? Bunun için bir neden göremiyorum. – Holger
Sınıfın tanımı sırasında ClassLoader, Lock (eşitleme (bu)) olarak kullanılır. Bir çağrı MultiClassLoader'da loadClass() yapıldığında, bu ClassLoader da eşitlenir. Araçlar: JarClassLoader eşitlenmeden önce ebeveyn (MultiClassLoader) eşitlendiğinde durumlar vardır. Bu durumda bir kilitlenme içine gireceksin. Senkronize ederek bu çıkmazdan kaçabilirsiniz. –
Daha fazla senkronizasyon eklemenin bir kilitlenmeden nasıl kaçınabileceğini göremiyorum. Sorunuz bu kavramın işe yaramadığını kanıtlıyor. Ancak umarım cevabım yardımcı olacaktır. – Holger