3

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?

niellus16
  • 51
  • 1
  • 3
  • Have you checked http://stackoverflow.com/a/15157131/823393 ? – OldCurmudgeon Sep 16 '16 at 14:32
  • @OldCurmudgeon yes, that answer basically points to the solution that's also described in the paged linked above. However, I don't know were to put that method and what other changes are required to make it work. – niellus16 Sep 16 '16 at 14:34
  • 1
    Why do you even use different class loaders - application server environment? – home Sep 16 '16 at 15:26
  • Yes, this code is used in a CloverETL environment, which apparently uses different class loaders – niellus16 Sep 19 '16 at 06:08

1 Answers1

3

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.

fgb
  • 18,439
  • 2
  • 38
  • 52
  • Thanks for your answer! I've just tried this solution and as you already thought: it doesn't work as it still results in multiple singleton instances. The code runs in a CloverETL environment, so I'll ask them why multiple class loaders are being used and whether they have a solution for this. – niellus16 Sep 19 '16 at 06:21
  • One reason for multiple classloaders is an OSGI Environment, where each bundle has its own classloader. In OSGI this is something good and desirable. But leads to issues like this question. – Christoph Oct 16 '19 at 20:06