Singleton Patterns
In this module, we are going to cover the Singleton Pattern. The Singleton Pattern is one of, if not the most, heavily used design patterns because of its simplicity to implement and the type of problem that it solves.
Concepts
The concepts when choosing a singleton pattern are that it guarantees only one instance is going to be created. It also guarantees the control of a resource. Since this is a creational design pattern, the instantiation of it is all controlled through the implementation of the pattern. Although, it doesn’t have to be, it is usually lazily loaded. This ties nicely with it being a creational pattern.
Examples of this in Java API or commonly used frameworks are the Runtime Environment, Logger, but depending upon the implementation this could be Factory instead of Singleton, and we shall discuss this in more detail later. Sprin Beans, if you have used the Spring Framework at all, you will quickly learn that all Spring Beans are by default Singletons. The fourth example can be Graphics Manager. When you are using a Graphics API of any kind you are going to get an instance of your graphical environment, and we only want only a single instance of those at a time.
Design – Considerations
The singleton is responsible for creating itself and managing its life-cycle. It is static in nature, although it is not implemented using a static class typically.
The reason for not using a static class is that it needs to be thread safe, and static doesn’t necessarily guarantees this for us. There is a private instance of a singleton, hence the minus sign or hyphen in the UML. There is also a private constructor that is marked the same way. This is because we want the singleton itself to call the constructor and nobody else. There are no parameters, and if you require parameters that is typically a Factory Pattern and violates the rules of a singleton.
Example – Runtime
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package ooad; /** * * @author Dhiraj Jha */ public class Singleton { public static void main(String[] args) { Runtime singletonRuntime = Runtime.getRuntime(); singletonRuntime.gc(); System.out.println(singletonRuntime); Runtime anotherInstance = Runtime.getRuntime(); System.out.println(anotherInstance); if(singletonRuntime == anotherInstance){ System.out.println("They are the same instance"); } } } |
Exercise – Create a Singleton
In this demo, we are going to create a singleton and then we are going to demonstrate that only one instance of our object will be instantiated. Later, we are going to convert it to be lazily loaded and finally, make it thread-safe singleton.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package ooad; /** * * @author Dhiraj Jha */ public class DbSingleton { //Eagerly Loading, runs when the JVM is loaded private static DbSingleton instance = new DbSingleton(); //private constructor private DbSingleton() { //do nothing, it is there just to restrict object creation from outside } //a public method to get the instance information public static DbSingleton getInsance() { if (instance == null) { instance = new DbSingleton(); } return instance; }//method ends }//class ends |
The implementation of the above class is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package ooad; import java.sql.*; /** * * @author Dhiraj Jha */ public class DbSingletonTest { public static void main(String[] args) { DbSingleton instance = DbSingleton.getInsance(); System.out.println(instance); //but if I use new operator to create the instance, it won't allow //DbSingleton secondInstance = new DbSinleton(); //the constructor is privately declared, so cannot be accessed DbSingleton anotherInstance= DbSingleton.getInsance(); System.out.println(anotherInstance); if(instance == anotherInstance){ System.out.println("They are same objects"); }//if ends }//main ends }//class ends |
Let’s code the same class so that there is lazy loading.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package ooad; /** * * @author Dhiraj Jha */ public class DbSingleton { //Lazy Loading, runs only when the getInstance() is invoked private static DbSingleton instance = null; //private constructor private DbSingleton() { //do nothing, it is there just to restrict object creation from outside } //a public method to get the instance information public static DbSingleton getInsance() { if (instance == null) { synchronized(DbSingleton.class){ //synchronized method is there to make it thread safe if(instance == null){ instance = new DbSingleton(); }//if ends }//sync method ends }//outer if ends return instance; }//method ends }//class ends |
Let’s make it proper use for creating a database connection and create a table using that connection to see performance enhancement and resource control as there will be a single instance which connects to the database.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package ooad; import java.sql.*; /** * * @author Dhiraj Jha */ public class DbSingleton { //Eagerly Loading, runs when the JVM is loaded private static DbSingleton instance = null; private static String user="root"; private static String password=""; private static String connString="jdbc:mysql://localhost:3306/shopping"; private Connection conn = null; //private constructor private DbSingleton(){ } //create a getCOnnection method public Connection getConnection(){ if (conn == null) { synchronized (DbSingleton.class) { if (conn == null) { try { conn = DriverManager.getConnection(connString, user, password); } catch (SQLException e) { System.out.println("Some error " + e.getStackTrace()); } } }//synchronized ends }//outer if ends return conn; } //a public method to get the instance information public static DbSingleton getInsance(){ if(instance == null){ synchronized(DbSingleton.class){ if(instance == null){ instance = new DbSingleton(); } } } return instance; } } |
and it’s revised implementation class would be like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package ooad; import java.sql.*; /** * * @author Dhiraj Jha */ public class DbSingletonTest { public static void main(String[] args) { DbSingleton instance = DbSingleton.getInsance(); // System.out.println(instance); // //but if I use new operator to create the instance, it won't allow // //us doing so // //DbSingleton anotherInstance = new DbSingleton(); // DbSingleton anotherInstance = DbSingleton.getInsance(); // System.out.println(anotherInstance); long timeBefore = 0; long timeAfter = 0; timeBefore = System.currentTimeMillis(); Connection conn = instance.getConnection(); timeAfter = System.currentTimeMillis(); //print the difference System.out.println(timeAfter - timeBefore); Statement sta; try{ sta = conn.createStatement(); int count = sta.executeUpdate("CREATE TABLE tbl_demo" + "(col1 int PRIMARY KEY, " + "col2 VARCHAR(60) NOT NULL" + ");"); System.out.println("Table Created"); }catch(SQLException e){ e.printStackTrace(); } //to see the difference, that only single instance has //been created timeBefore = System.currentTimeMillis(); Connection conn2 = instance.getConnection(); timeAfter = System.currentTimeMillis(); //print the difference System.out.println(timeAfter - timeBefore); } } |
All the codes are written in Netbeans IDE using MySQL Connector/J. I did not explain any of the SQL statements assuming that the one who is referring Design Patterns must have basic idea of Core Java.
Leave a Reply
You must be logged in to post a comment.