views:

151

answers:

4

My problem is that I'm working on a project that requires me to run multiple instances of someone elses code which has many static attributes/variables, which causes all the instances to share those resources and, well, crash. I can run multiple instances of this other person's program if I create a .jar file off of it and open it multiple times by running the .jar in windows, but running calling the "main" method multiple times in my code (which is what I need to do) won't work.

I thought about creating a .jar and using Runtime.getRuntime().exec( "myprog.jar" ); to call the program multiple times, but that won't work for me since I have to pass an instance of my object to this new program and I don't think this solution would allow for that.

PS: This is also posted in the Sun forums, so I`ll post the answer I get there here or the answer I get here there naturally giving proper credit once I this is solved =P.

A: 

The description is a little confusing.

If you are running the code multiple times, you are running multiple independent processes, each running in its own JVM. There is no way that they are actually sharing the values of their static fields. Java doesn't let you directly share memory between multiple VMs.

Can you elaborate more (ideally with examples and code) what the attributes are defined as and what kind of failures you are getting? This may be completely unrelated to them being static.

In particular, what exactly do you mean by shared resources? What resources are your programs sharing?

Uri
+8  A: 

Remember that a static element in Java is unique only in the context of a classloader (hierarchy); a class is uniquely identified in a JVM by the tuple {classloader, classname}.

You need to instantiate isolated classloaders and load the jar using that class loader. Each loaded class (and thus statis elements) are unique in their classloader and will not interfere with one another.

Could I get some pointers on how to instantiate isolated classloaders? I'm pretty new to this and Google sadly wasn't as clarifying as expected.
Andre Rodrigues
http://java.sun.com/docs/books/tutorial/deployment/jar/examples/JarClassLoader.java
+2  A: 

I'd say you have three alternatives:

  • Refactor the legacy application so that it doesn't use static attributes. If you can do this, this may be the best solution in the long term.

  • Continue with your approach of launching the legacy application in a separate JVM. There are a number of ways that you can pass (copies of) objects to another JVM. For example, you could serialize them and pass them via the child processes input stream. Or you could stringify them and pass them as arguments. In either case, you'll need to create your own 'main' class/method that deals with the object passing before calling the legacy app.

  • I think you should be able to use classloader magic to dynamically load a fresh copy of the legacy application each time you run it. If you create a new classloader each time, you should get a fresh copy of the legacy application classes with a separate set of statics. But, you have to make sure that the legacy app is not on your main classpath. The problem with this approach is that it is expensive, and you are likely to create memory leaks.

Stephen C
Option 3 is no slower than option 2... certainly much faster. I think the extra opportunity for memory leaks is also pretty slim. URLClassLoader and some reflection is all that's needed and GC should happen like anything else.
PSpeed
@PSpeed - the problem is that if *just one instance* of one of the dynamically loaded class leaks, this will entail the classloader and all of the other classes. I've heard stories of people being burned by this kind of thing ...
Stephen C
True, but I see that as no bigger a risk than anonymous inner classes as related to swing components. I've rarely met a swing program that didn't have several listener leaks (and associated references to the outer class). On the other hand, an isolated classloader plus a reflective entry point is pretty easy to get right... at least in comparison.
PSpeed
+1 for refactoring. Statics with mutable state are almost never a good thing, and usually worth the effort to rip them out.
CPerkins
A: 

The proper approach was already suggested - using custom ClassLoaders. Another thing comes to my mind, which might seem ugly, but will probably do, and is a bit more object-oriented approach.

The legacy code is used for its operations, and it incorrectly uses static instead of instance variables. You can fix that using inheritance and reflection:

  • create (or reuse) an utility class that copies instance variables to static ones
  • extend the classes in question and provide the same instance variables as the static ones
  • override all methods. In the overriding methods use the utility to copy the state of the current object to the static variables, and then delegate to (call) the super methods.

Then start using instance of your class, instead of the legacy ones. That way you will simulate the proper behaviour. Have in mind this is NOT thread-safe.

Bozho