Design patterns Singleton Lazy Singleton practical example in java


Example

Real life use cases for Singleton pattern;

If you are developing a client-server application, you need single instrance of ConnectionManager, which manages the life cycle of client connections.

The basic APIs in ConnectionManager :

registerConnection: Add new connection to existing list of connections

closeConnection : Close the connection either from event triggered by Client or Server

broadcastMessage : Some times, you have to send a message to all subscribed client connections.

I am not providing complete implementation of source code since example will become very lengthy. At high level, the code will be like this.

import java.util.*;
import java.net.*;

/* Lazy Singleton - Thread Safe Singleton without synchronization and volatile constructs */
final class  LazyConnectionManager {
    private Map<String,Connection> connections = new HashMap<String,Connection>();
    private LazyConnectionManager() {}
    public static LazyConnectionManager getInstance() {
        return LazyHolder.INSTANCE;
    }
    private static class LazyHolder {
        private static final LazyConnectionManager INSTANCE = new LazyConnectionManager();
    }

    /* Make sure that De-Serailzation does not create a new instance */
    private Object readResolve()  {
        return LazyHolder.INSTANCE;
    }
    public void registerConnection(Connection connection){
        /* Add new connection to list of existing connection */
        connections.put(connection.getConnectionId(),connection);
    }
    public void closeConnection(String connectionId){
        /* Close connection and remove from map */
        Connection connection = connections.get(connectionId);
        if ( connection != null) {
            connection.close();
            connections.remove(connectionId);
        }
    }
    public void broadcastMessage(String message){
        for (Map.Entry<String, Connection> entry : connections.entrySet()){
            entry.getValue().sendMessage(message);            
        }
    }    
}

Sample Server class:

class Server implements Runnable{
    ServerSocket socket;
    int id;
    public Server(){
        new Thread(this).start();
    }
    public void run(){
        try{
            ServerSocket socket = new ServerSocket(4567);
            while(true){
                Socket clientSocket = socket.accept();
                ++id;
                Connection connection = new Connection(""+ id,clientSocket);
                LazyConnectionManager.getInstance().registerConnection(connection);    
                LazyConnectionManager.getInstance().broadcastMessage("Message pushed by server:");
            }
        }catch(Exception err){
            err.printStackTrace();
        }
    }
    
}

Other practical use cases for Singletons:

  1. Managing global resources like ThreadPool, ObjectPool, DatabaseConnectionPool etc.
  2. Centralised services like Logging application data with different log levels like DEBUG,INFO,WARN,ERROR etc
  3. Global RegistryService where different services are registered with a central component on startup.That global service can act as a Facade for the application