Java SingletonIntroduction What is a Singleton? The Singleton pattern became widely popular when it was included in the now famous "Gang of Four" Patterns book. Its general objective is to make sure that only one instance of a specific object type exists. The classic code snippet used to create a Singleton is as follows:

public class Singleton { private static Singleton instance = null;   public synchronized Singleton static getInstance() { if (instance == null) instance = new Singleton(); return instance; } } Some examples of a Singleton use the "Double Checked Locking method" to create the Singleton. public class Singleton { private static Singleton instance = null;   public Singleton static getInstance() { if (instance == null) { synchronize(this) { if (instance == null) instance = new Singleton(); } } return instance; } } This method of "optimizing" the synchronization block has been shown not to work. Singletons are commonly found in C++ and J2SE applications. However their use in distributed J2EE environment becomes a lot more complex and subject to debate. Synchronization Lots of common enterprise requirements are implemented to some degree by the J2EE Container. One of these classic requirements is the need for multi-threading in enterprise applications. This is generally implemented by the use of a thread pool. Each client request coming in is assigned a worker thread to service the request. Since therefore any J2EE application by its nature is multithreaded, limiting the synchronization of threads is an important requirement. "Synchronized" as shown is used on a Singletons getInstance method. This is to prevent the "==null" test which is not thread safe causing the creation of two Singleton objects, one of which will then end up being thrown away. There is a way around the "synchronize" issue by using a "startup class" or a "startup Servlet". Since both these types of objects are initialized at container start up it is possible to use them to initialize the Singletons you need. It is then safe to drop the "synchronized" from the "getInstance" method. The following StartUpServlet initializes several Singletons in its init method. This approach relies on the tag to being placed in the Web Applications web.xml deployment descriptor. public class StartUpServlet extends HttpServlet { public void init() throws ServletException { try { // Initialize the Singletons. EJBController.initInstance(); CacheManager.initInstance(); RMISingletonWrapper.initInstance(); DAOFactory.initInstance(); ServiceLocator.initInstance(); } catch (Exception e) { e.printStackTrace(); } }   public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {} } Clustering and RMI Singletons Clustering is when you have J2EE containers that are running on different VMs talk to each other. Clustering is used to provide load balancing and fail over for J2EE clients. The simple/local Singleton as shown is a non distributed object. Therefore in a clustered environment you will end up with at least one Singleton object on each server. This of course may be ok for the design requirements. However if the design is to have one Singleton for the cluster then a common approach is to implement a "pinned service". This refers to an RMI object that is only located on one container in the cluster. Its stub is then registered on the clustered JNDI tree making the object available cluster wide. This raises of causes one issue, what happens when the server containing the RMI Singleton crashes? A Container in the cluster could try to bind a new RMI Singleton if it notices it is missing out of the JNDI tree. However this could cause issues if all the containers try to bind new RMI Singletons at the same time in response to a failure. Generally at the end of the day RMI Singletons do tend to have the draw back that they end up as single points of failure. In the following code example a local Singleton is used to act as a Wrapper around a RMI object that is bound into the clusters JNDI tree. public class RMISingletonWrapper { private static RMISingletonWrapper instance = null; private static String SINGLETON_JNDI_NAME = "RMISingleton"; public static RMISingletonWrapper getInstance() { return instance; } // All methods in delegate the method call to the actual Singleton that lives on the // clustered JNDI tree. public void delegate() { try { RMISingleton singleton = getRMISingleton(); singleton.delegate(); } catch (Exception e) { // Could try and recover e.printStackTrace(); } } // Locate the true Singleton object in the cluster. private RMISingleton getRMISingleton() { RMISingleton rmiSingleton = null; try { Context jndiContext = new InitialContext(); Object obj = jndiContext.lookup(SINGLETON_JNDI_NAME); rmiSingleton = (RMISingleton)PortableRemoteObject.narrow(obj, Class.forName("examples.singleton.rmi.RMISingleton")); } catch (Exception e) { // Could try and recover e.printStackTrace(); } return rmiSingleton; } } Distributed Singleton Caches One of the most common usages of Singletons is as caches of data. This use has issue for non RMI Singletons in a clustered environment. Problems happen when you attempt to do an update to the cache. Since a Singleton instance exists on each Container any update to the cached data by one Singleton will not be replicated to the other Singletons that exist on the other Containers. This issue can be resolved by the use of the Java Messaging API to send update messages between Containers. In this approach if an update is made to the cache on one Container a message is published to a JMS Topic. Each Container has a listener that subscribes to that topic and updates its Singleton cache based on the messages it receives. This approach is still difficult as you have to make sure that the updates received on each container are handled in a synchronous fashion. JMS messages also take time to process so the caches may spend some time out of sync. In the following simplistic implementation of a distributed Cache a CacheManager Singleton holds a Map of cached items. Items to be cached are placed in a CachItem object which implements the ICacheItem interface. The CacheManager does not make any attempt to old remove items from the Cache based on any criteria like "Last Accessed Time". public class CacheManager implements javax.jms.MessageListener { public static CacheManager instance=null; public static Map cache = new HashMap(); private TopicConnectionFactory topicConnectionFactory = null; private TopicConnection topicConnection = null; private TopicSession topicSession = null; private Topic topic = null; private TopicSubscriber topicSubscriber = null; private TopicPublisher topicPublisher = null; private final static String CONNECTION_FACTORY_JNDI_NAME = "ConnectionFactory"; private final static String TOPIC_NAME = "TopicName"; public static void initInstance() { instance = new CacheManager(); } public static CacheManager getInstance() { return instance; } public synchronized void addCacheItem(ICacheItem cacheItem) { CacheMessage cacheMessage = new CacheMessage(); cache.put(cacheItem.getId(), cacheItem.getData()); cacheMessage.setMessageType(CacheMessage.ADD); cacheMessage.setCacheItem(cacheItem); sendMessage(cacheMessage); } public synchronized void modifyCacheItem(ICacheItem cacheItem) { CacheMessage cacheMessage = new CacheMessage(); cache.put(cacheItem.getId(), cacheItem.getData()); cacheMessage.setMessageType(CacheMessage.MODIFY); cacheMessage.setCacheItem(cacheItem); sendMessage(cacheMessage); } public ICacheItem getCacheItem(String key) { return (ICacheItem)cache.get(key); } private CacheManager() { try { InitialContext context = new InitialContext(); topicConnectionFactory = (TopicConnectionFactory) context.lookup(CONNECTION_FACTORY_JNDI_NAME); topicConnection = topicConnectionFactory.createTopicConnection(); topicSession = topicConnection.createTopicSession(false,Session.AUTO_ACKNOWLEDGE); topic = (Topic) context.lookup(TOPIC_NAME); topicSubscriber = topicSession.createSubscriber(topic); topicSubscriber.setMessageListener(this); topicPublisher = topicSession.createPublisher(topic); topicConnection.start(); } catch (Exception e) { e.printStackTrace(); } } public void onMessage(Message message) { try { if (message instanceof ObjectMessage) { ObjectMessage om = (ObjectMessage)message; CacheMessage cacheMessage = (CacheMessage)om.getObject(); ICacheItem item = cacheMessage.getCacheItem(); interpritCacheMessage(cacheMessage); } } catch (JMSException jmse) { jmse.printStackTrace(); } } private void interpritCacheMessage(CacheMessage cacheMessage) { ICacheItem cacheItem = cacheMessage.getCacheItem(); if (cacheMessage.getMessageType()==CacheMessage.ADD) { synchronized (this) { cache.put(cacheItem.getId(), cacheItem.getData()); } } else if (cacheMessage.getMessageType()==CacheMessage.MODIFY) { synchronized (this) { cache.put(cacheItem.getId(), cacheItem.getData()); } } } private void sendMessage(CacheMessage cacheMessage) { try { Message message = topicSession.createObjectMessage(cacheMessage); topicPublisher.publish(message); } catch (Exception e) { e.printStackTrace(); } } } Class Loading Containers tend to implement their own class loading structures to support hot deployment for J2EE components and class isolation WAR files. Class isolation in WAR files means that all classes found in a WAR file must be isolated from other deployed WAR files. Each WAR file therefore is loaded by a separate instance of the Class loader. The purpose is to allow each WAR file have its own version of commonly named JSPs like "index.jsp". If a Singleton class is located in several WAR files it will mean that a separate Singleton instance will be created for each WAR file. This may of course be ok for the required design but it is worth being aware of. Common Implementations of a Singleton in J2EE In conclusion I would like to talk about the three most common implementations of the Singleton pattern in J2EE I have come across. These are as Service Locators, Object Factories and Controllers. A Service Locator allows you to cache objects (like EJB homes) that are located in the JNDI tree. JNDI look ups are very expensive so using a Singleton to cache these objects is a good idea. Since you never update these objects it does not matter that the cache is not distributed across a cluster. In the following implementation of a ServiceLocator all lookups into the JNDI tree are cached into a Map. The ServiceLocator's getService method has a threading issue where it could place the JNDI Object into the map multiple times. This is due to the fact that the check to see if the object is already in the cache is not synchronized. The reason for dropping the synchronization is that it is more costly to do a "synchronization" than just ignoring an issue that if it happened would cause no real harm. public class ServiceLocator { private static ServiceLocator instance = null; private Map cache = null; private ServiceLocator() throws NamingException { cache = Collections.synchronizedMap(new HashMap()); } public static ServiceLocator getInstance() throws NamingException { return instance; } public static void initInstance() throws NamingException { Iinstance = new ServiceLocator(); } public Object getService(String entityName) throws NamingException { Object home = this.getFromCache(entityName); if (home == null) { try { Context jndiContext = new InitialContext(); home = jndiContext.lookup(entityName); } catch (NamingException e) { e.printStackTrace(); } this.putInCache(entityName, home); } return home; } private void putInCache(String key, Object value) { cache.put(key, value); } private Object getFromCache(String key) { return cache.get(key); } } An Object Factory class allows you to create an object of a certain type based on some form of an identifier. A common use of a factory in J2EE is in the creation of Data Access Objects. DAO's are commonly used to abstract SQL usage into specific classes. Clients obtain a factory Singleton and pass in the specific identifier for the specific DAO they need. The Object Factory instantiates the object and then returns a common interface to the client. To allow possible support of multiple databases, a simple trick that can be used is to append a specific identifier to the DAO's class name. The implementer of the DAO class can then provide a specific implementation of the DAO for each database type if required. It is possible that the factory could be implemented as a bunch of static methods. A reason not to take the static approach is the fact that maybe at some point the caching of DAO's will be required. If caching is required than the factories implementation can be changed to support caching without changing the factories interface. public class DAOFactory { private static DAOFactory instance = null; private String nameAppender = null; private final String ORACLE_DAO = "OracleDAO"; private final String SQLServer_DAO = "SQLServerDAO"; private DAOFactory() { // Maybe get this from a properties file nameAppender = ORACLE_DAO; } public static DAOFactory getInstance() { return instance; } public static void initInstance() { instance = new DAOFactory(); } public IDAO getDAO(String daoName) throws DAOException { IDAO aDAO = null; try { aDAO = (IDAO) Class.forName(daoName + nameAppender).newInstance(); } catch (ClassNotFoundException cnfex) { throw new DAOException(cnfex); } catch (IllegalAccessException ilaex) { throw new DAOException(ilaex); } catch (InstantiationException instex) { throw new DAOException(instex); } catch (Exception e) { throw new DAOException(e); } return aDAO; } }   A Controller takes a request and based on some criteria directs that request to an object to be serviced. Since the container is running multiple threads and garbage collection is expensive it would be nice to have just one instance of the controller. A Singleton therefore is a good protocol independent Controller. In the following implementation of an EJB Controller, the processRequest method takes a Request object that specifies the following; the Stateless EJBs Home interface class name, the Home interfaces JNDI name, the method name within the Stateless EJB to call and finally the list of parameters to pass in. The Response object contains the return object from the method call. public class EJBController { private static EJBController instance = null; public static void initInstance() { instance = new EJBController(); } public static EJBController getInstance() { return instance; } public Response processRequest(Request request) { Parameter ret = null; Object[] args = null; Class[] argTypes = null; Response response = new Response(); List methodParameters = request.getMethodParameters(); String methodName = request.getMethodName(); if (methodParameters != null) { int parametersCount = methodParameters.size (); args = new Object[parametersCount]; argTypes = new Class[parametersCount]; for (int i = 0; i < parametersCount; i++) { Parameter param = (Parameter) methodParameters.get(i); args[i] = param.getValue (); argTypes[i] = param.getType (); } } try { EJBObject remoteObjRef = locateRemote(request); Class targetClass = remoteObjRef.getClass(); Method m= targetClass.getMethod (methodName, argTypes); Object returnObject = m.invoke(remoteObjRef, args); response.setReturnObject(returnObject); } catch (InvocationTargetException e) { Throwable e1 = e.getTargetException(); e1.printStackTrace(); } catch (Throwable t) { t.printStackTrace(); } return response; } // Locate the home interface of the JNDI tree and call its create method private EJBObject locateRemote(Request request) { String homeInterfaceName = request.getHomeInterfaceName(); String jndiName = request.getJNDIName(); EJBObject remoteObjRef = null; try { Object obj = ServiceLocator.getInstance().getService(jndiName); EJBHome home = (EJBHome) PortableRemoteObject.narrow(obj, Class.forName(homeInterfaceName)); Method createMethod = home.getClass().getMethod("create", new Class[0]); remoteObjRef = (EJBObject) createMethod.invoke((Object) home, new Object[0]); } catch (Exception e) { e.printStackTrace(); } return remoteObjRef; } } The Singletons presented here as common implementations of the pattern in J2EE can be thought of as either stateless or ones that at most control resources/objects that do not need to be cluster aware.