【发布时间】:2014-07-17 14:35:17
【问题描述】:
我的程序的总体概念包括从 .class 文件加载插件、运行它、关闭它、手动更新 .class 文件,最后重新打开它。目前它
- 通过
URLClassLoader加载.class 文件并开始执行main 方法。 - main 方法生成另一个线程 (VIA
ScheduledThreadPoolExecutor),它会定期查询服务。 - 产生一个新线程来处理清理:
- 在
ScheduledThreadPoolExecutor上调用.shutdown(),所有线程都死掉了。 - 在
URLClassLoader上调用.close()并将URLClassLoader变量设置为null。
- 在
- 然后清理线程休眠以允许手动替换 .class 文件。
- 清理线程然后重新启动进程,加载新的 .class 文件并运行它们。
在这些步骤中一切正常,新的 .class 文件按预期工作。
当插件再次启动时,我遇到的问题就开始了。每次运行重新启动过程时,它都会产生一个额外的插件实例。
第一次运行:1 个正在运行的插件
第二次运行:2 个正在运行的插件
第 3 次运行:3 个正在运行的插件
等等
我觉得奇怪的是,每次启动时它不会产生两倍的插件数量,它只会产生一个额外的插件。额外的代码只能再执行一次,而不是由之前的每个线程执行。每次对startup() 的第二次调用会创建一个新的URLClassLoader(旧的已关闭并无效),是否也会以某种方式启动所有过去的URLClassLoaders?尝试在调试模式下运行它,它并没有跟踪每个活动线程。我需要维护以前的URLClassLoader,没有它对在后台运行的现有对象的任何引用都将被删除。
鉴于程序的复杂性,很难给出 SSCCE。
public class PluginHandler
{
private static URLClassLoader cl = null;
private static String = "somedir";
public void restart()
{
(new Thread() {
public void run() {
if (cl != null) {
cl.invokeClass(pckg, "main", "-shutdown");
cl.close();
cl = null;
}
try {
Thread.sleep(15000);
} (catch InterruptedException e) {
System.out.println("Interrupted");
}
cl = URLClassLoader cl = new URLClassLoader(new URL[] { new File(path).toURI().toURL() } ));
cl.invokeClass(pckg, "main", "-startup");
}).start();
}
public URLClassLoader invokeClass(String pckgName, String mthdName, String[] args)
throws Exception
{
Class<?> loadedClass = cl.loadClass(pckgName);
Method m = loadedClass.getMethod(mthdName, args.getClass());
m.invoke(null, new Object[] { args });
return urlcl;
}
}
public class PluginMain
{
public static void main(String[] args) {
if (args[0].equals("-startup") {
new PluginController.run();
}
else if (args[0].equals("-shutdown") {
PluginController.shutdown();
}
}
}
public class PluginController implements Runnable
{
static ScheduledThreadPoolExecutor st;
static ScheduledFuture<?> sf;
public void run() {
st = new Scheduled ThreadPoolExecutor(1);
sf = st.scheduleWithFixedDelay(new Plugin(), 0, 10, Time_Unit.SECONDS);
sf.wait();
System.out.println("Returns from run()"); //prints after shutdown is run.
}
public static void shutdown() {
sf.cancel();
st.shutdown();
}
}
public class Plugin implements Runnable
{
public void run() {
//Queries some service
}
}
编辑:所有插件同时运行相同的代码行。我提到了那些睡眠,我怀疑这会使不同的线程无法完全同步。
【问题讨论】:
-
也许这与元/永久代空间有关。类加载器加载的插件的第一个实例继续运行,因为它永远不符合 GC 条件?与后续加载相同。
-
哦,我没有提到。所有插件同时运行相同的代码行。我提到了那些睡眠,我怀疑这会使不同的线程无法完全同步。
标签: java multithreading