问题
I have a simple singleton class in Java that looks like the following one:
public class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
public void doSomething(){
...
}
}
My code also contains two classes, from now on called A and B, that both have the following structure:
public class Foo{
...
public void bar(){
...
Singleton.getInstance().doSomething();
...
}
...
}
During an execution the code in class A is executed first and therefore it silently instantiates the singleton instance. However, later on when B's code gets executed, the singleton instance is instantiated again, which is not what I want to achieve.
After a little investigation we found that class A and B use a different class loader, which means the singleton class is also loaded twice, resulting into two singleton instances.
I've looked for solutions to this issue on the web and found several (quite similar) pages, e.g. http://www.javaworld.com/article/2073352/core-java/simply-singleton.html?page=2 and http://snehaprashant.blogspot.nl/2009/01/singleton-pattern-in-java.html.
However, after trying out several options I still can't get it to work, mainly because I don't really know how to apply the solution(s) in the simple code listed above.
So my question is: can someone provide me with a (clue to a) practical solution for my code to the problem described above so that the singleton is only instantiated once regardless of the classloader being used?
回答1:
I doubt the solution in the JavaWorld article works. getContextClassLoader()
, and Singleton.class.getClassLoader()
can return different classloaders each time. And if you got a consistent classloader, then the only way to use the class would be via reflection.
I guess they expect you to replace:
Singleton.getInstance().doSomething();
with:
try {
Object instance = getClass("package.Singleton").getMethod("getInstance").invoke(null);
instance.getClass().getMethod("doSomething").invoke(instance);
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
Instead, I would look at why there are multiple classloaders. Either keep all your code under the same classloader, or put the singleton into a common parent of both classloaders, and make the class unavailable to the child classloaders.
来源:https://stackoverflow.com/questions/39533902/java-singleton-usage-with-multiple-class-loaders