Having 2 instances of a Singleton!!

Who said only one instance of a Singleton can live in a JVM?
Assume we have a singleton class written correctly to avoid having 2 instancea by a multithreading trick. Is there any method by which we can have 2 instances from this class? The answer is yes!

First let's see how can the singleton class be written with a tester main method.

  1. public class SingletonTest {
  2. public static void main(String[] args) throws Exception {
  3. Singleton singleton1 = Singleton.getSingleton();
  4. Singleton singleton2 = Singleton.getSingleton();
  5.  
  6. System.out.println(singleton1);
  7. System.out.println(singleton2);
  8. }
  9.  
  10. private static class Singleton {
  11.  
  12. private static Singleton singleton;
  13.  
  14. private Singleton() {
  15. }
  16.  
  17. public synchronized static Singleton getSingleton() {
  18. if (singleton == null) {
  19. singleton = new Singleton();
  20. }
  21. return singleton;
  22. }
  23. }
  24. }

When we run this code, we can see the address of the objects printed which ensures both references are pointing to the same object.
Output can be like this

  1. singletontest.SingletonTest$Singleton@5dcdd76a
  2. singletontest.SingletonTest$Singleton@5dcdd76a

The trick is just simple, let's let another class loader load the same class, calling the getter method on the newly loaded class by the other class loader will simply return another instance of the same class.

All the trick is to write a new class loader that doesn't delegate loading the class to its parent (the default class loader) and reloads it itself.
It can be as simple as this

  1. public class SingletonTest {
  2.  
  3. ....
  4.  
  5. private static class MyClassLoader extends ClassLoader {
  6.  
  7. @Override
  8. public Class<?> loadClass(String s) {
  9. return findClass(s);
  10. }
  11.  
  12. @Override
  13. public Class<?> findClass(String s) {
  14. try {
  15. byte[] bytes = loadClassData(s);
  16. return defineClass(s, bytes, 0, bytes.length);
  17. } catch (IOException ioe) {
  18. try {
  19. return super.loadClass(s);
  20. } catch (ClassNotFoundException ignore) {
  21. }
  22. ioe.printStackTrace(System.out);
  23. return null;
  24. }
  25. }
  26.  
  27. private byte[] loadClassData(String className) throws IOException {
  28. File f = new File("build/classes/" + className.replaceAll("\\.", "/") + ".class");
  29. int size = (int) f.length();
  30. byte buff[] = new byte[size];
  31. dis.readFully(buff);
  32. dis.close();
  33. return buff;
  34. }
  35. }
  36. }

Now all what we need is to modify the main method and ask our new class loader to load the same class, then call the getter method on the newly loaded class, reflection will be a good way to do that!

  1. public class SingletonTest {
  2.  
  3. public static void main(String[] args) throws Exception {
  4. Singleton singleton1 = Singleton.getSingleton();
  5. Singleton singleton2 = Singleton.getSingleton();
  6.  
  7. MyClassLoader classLoader = new MyClassLoader();
  8. Method method = classLoader.loadClass("singletontest.SingletonTest$Singleton").getMethod("getSingleton");
  9. method.setAccessible(true);
  10. Object singleton3 = method.invoke(null);
  11.  
  12. System.out.println(singleton1);
  13. System.out.println(singleton2);
  14. System.out.println(singleton3);
  15. }
  16.  
  17. ....
  18. }

Now the output can be like this

  1. singletontest.SingletonTest$Singleton@5dcdd76a
  2. singletontest.SingletonTest$Singleton@5dcdd76a
  3. singletontest.SingletonTest$Singleton@74f9a042

As we can see the third reference is pointing to a different address which means, another instance of the singleton class!

That's it!