//
you're reading...
General

Java Singleton Pattern

The singleton pattern is the most popular pattern in Java. But as popular as it is, it is a pattern which has a number of ways in which it can be implemented and in which lots of corner cases exist which developers seem to take for granted. So, let me just devote this blog to the Singleton pattern and list out the things I have used in my projects.

There are many ways to implement a singleton.

Option 1:
public class Singleton
{
    private static final Singleton SINGLE_INSTANCE = new Singleton();
    private Singleton()
    {
    }

    public static Singleton getInstance() { return SINGLE_INSTANCE; }
};

In the above, a single instance is created when the class is loaded. This can be done as shown above or inside a static block. The advantage of it is, the class loader synchronizes the loading of a class and hence ensures that only one instance is instantiated even when there are multiple threads contending for the same instance. To construct the singleton at the time of class loading, all data required for construction should be know upfront. If runtime data is required we have to change the implementation as below:

Option 2:
public class Singleton
{
    private static final Singleton SINGLE_INSTANCE;

    private Singleton(String someparam)
    {
         //do processing
    }

    public static synchronized Singleton getInstance(String someparam) 
    { 
        if (SINGLE_INSTANCE == null)
            SINGLE_INSTANCE = new Singleton(someparam);
        return SINGLE_INSTANCE; 
    }
};

Note the synchronized keyword in the method. This ensures it is thread safe. But obviously once the instance is created, this will act as a bottleneck for all threads accessing the single instance. In a better approach create two methods, synchronized createInstance and a getInstance as below:

    public static synchronized void createInstance(String someparam) 
    { 
        if (SINGLE_INSTANCE == null)
            SINGLE_INSTANCE = new Singleton(someparam);
    }
    public static Singleton getInstance(String someparam) 
    { 
        //only locks if the instance needs to be created, else different threads can access.
        if (SINGLE_INSTANCE == null)
            createInstance(someparam); 
        return SINGLE_INSTANCE; 
    }

Note, both the methods check for the SINGLE_INSTANCE for null. This ensures when multiple threads contend for createInstance, only the first thread actually creates the object.

But any of the above approaches to a singleton has one major problem. This is a Singleton for <b>ONE CLASSLOADER<b> and not for the whole JVM. Each classloader that loads the Singleton class will create a new instance of the object. To test bring out this disadvantage, write a multi-threaded application that uses the Singleton class as below:

 A runnable that can run the singleton in a different classloader
public class SingletonRunnable implements Runnable
{
    public void run()
    {
        Singleton single = Singleton.getInstance("Test1");
        System.out.println("Instance is: " + single + ":" + single.getClass().getClassLoader());
    }
}

 A Non-delegating class loader so that we can force the class to be loaded by different class loaders
     public static class MyClassLoader extends URLClassLoader   
     {
        private String _name; //store the name so we can recognize what is happening
        public MyClassLoader(URL[] urls, String nm)
            throws Exception
        {
            super(urls);
            _name = nm;
        }

        @Override
        protected synchronized Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
        {
            Class<?> cls = findLoadedClass(name);
            if (cls != null)
                return cls;

            try
            {
                cls = this.findClass(name);
                if ((cls != null) && (resolve))
                {
                    resolveClass(cls);
                    return cls;
                }
            }
            catch (ClassNotFoundException e)
            {
                cls = super.loadClass(name, resolve);
            }

            return cls;
        }

        public String toString()
        {
            return _name;
        }
    }

 Now we will invoke the class in two classloaders as below 
    public static void main(String[] args)
        throws Exception
    {
         MyClassLoader ldr = new MyClassLoader(new URL[] { new URL("file:///home/rsankar/research/") }, "LoaderTest1");
         Class cls = ldr.loadClass("SingletonRunnable");
         Runnable run = (Runnable)cls.newInstance();
         Thread thrd = new Thread(run);
         thrd.start();
         thrd.join();

         MyClassLoader ldr2 = new MyClassLoader(new URL[] { new URL("file:///home/rsankar/research/")}, "LoaderTest2");
         Class cls2 = ldr2.loadClass("SingletonRunnable");
         Runnable run2 = (Runnable)cls2.newInstance();
         Thread thrd2 = new Thread(run2);
         thrd2.start();
         thrd2.join();
    }

When we run this code,  the output is as below. As we can see, two instances of the Singleton class are created.

Instance is: Singleton@de6ced:LoaderTest1
Instance is: Singleton@14318bb:LoaderTest2

So, how do we create a JVM Singleton?

One way to do it is to force the subsequent classloaders to load the class using the boot classloader. Say we change the getInstance in the above method as this below:

 private Singleton getInstance(String someparam)
    {
        ... code as before ...
    }

    public static Object getVMSingleInstance(String someparam)
        throws Exception
    {
       //this gets the system class loader
        ClassLoader syscl = Singleton.class.getClassLoader().getSystemClassLoader();
        Class cls = syscl.loadClass("Singleton");
        Method mthd = cls.getDeclaredMethod("getInstance", String.class);
        mthd.setAccessible(true);
        Object obj = mthd.invoke(null, someparam);
        return obj;
    }

Here, we have declare getInstance as private, and provide a getVMSingleInstance. This forces the Singleton class to be loaded using the boot classloader. Now we can change our runnable as below and run the sample again:

public class SingletonRunnable implements Runnable
{
    public void run()
    {
        try
        {
        Object single = Singleton.getVMSingleInstance("Test1");
        System.out.println("Instance is: " + single + ":" + single.getClass().getClassLoader());
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

Now running the invoker gives the following output:

Instance is: Singleton@de6ced:sun.misc.Launcher$AppClassLoader@35ce36
Instance is: Singleton@de6ced:sun.misc.Launcher$AppClassLoader@35ce36

From above we see, we have got a truly Single instance across classloaders. But this has the disadvantage that all methods in the singleton class has to be invoked using reflection.

Advertisements

Discussion

No comments yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: