Reputation: 207
The overall concept of my program involves loading a plugin from .class files, running it, shutting it down, manually updating the .class file, and finally turning it back on. Currently it
URLClassLoader
and begins execution of the main method. ScheduledThreadPoolExecutor
) which queries a service every regularly. .shutdown()
on ScheduledThreadPoolExecutor
, and all threads die. .close()
on URLClassLoader
and sets URLClassLoader
variable to null. Everything during these steps works, and the new .class files work as expected.
The issue I'm running into begins when the plugin is started again. Each time it runs through the restart process, it spawns one extra instance of the plugin.
1st run: 1 running plugin
2nd run: 2 running plugins
3rd run: 3 running plugins
and so on
What I find strange is that it isn't spawning double the amount of plugins on each start, it's only spawning one additional. The extra piece of code must only be executed one additional time, rather than by each previous thread. Could each subsequent second call to startup()
, which creates a new URLClassLoader
(the old one is closed and nulled out), also start up all of the past URLClassLoaders
somehow? Tried running this in debug mode, and it isn't tracking every active thread. I need to maintain the previous URLClassLoader
, without it any reference to existing objects running in the background are removed.
Hard to give SSCCE given the complexity of the program.
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
}
}
Edit: All plugins are running the same lines of code at the same time. I mentioned those sleeps, which I suspect would throw off the different threads from being completely synchronized.
Upvotes: 4
Views: 271
Reputation: 207
Mark W's suggestion lead me down a rabbit hole of using jmap and other process analysis programs to find out what exactly was going on. There's a ton of useful utilities out there. With the combination of VisualVM and Eclipse Memory Analyzer (MAT) I was able to figure out that I wasn't closing the FileHandler for my log. So many hours down the drain!
Upvotes: 1