April 24, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Global Variables in Java with the Singleton Pattern

  • February 23, 2000
  • By Wiebe deJong
  • Send Email »
  • More Articles »

Java and C++ are quite similar, and this makes it relatively easy for C++ programmers to learn the newer language. There are a few areas, however, that are different enough to cause problems, and one of these is the lack of global variables. This can be overcome in Java with the application of the Singleton design pattern. This article will look at the use of this pattern as an aid to C++ developers who are making the move to Java and who want to be productive now by putting off the transition to no global variables to a later date, flattening the learning curve somewhat.

The Singleton pattern ensures that only one instance of a class will be created and provides a global point of access to it. Any global variables that are required can then be placed within this class and accessed wherever they are needed. Gamma et al. describe the Singleton pattern in C++ in their book Design Patterns: Elements of Reusable Object-Oriented Software. In this article, I will develop the Singleton pattern, improve it, then show how it can be used to implement global variables in Java.

Basic Singleton Class

Java does not support global variables. While purists say this is a good thing, is does present a considerable stumbling block to C++ programmers who are used to developing with them. Every variable in Java must be declared within a class. However, Java uses the
static
keyword to indicate that a particular variable is a class variable rather than an instance variable. What this means is that there will be only one copy of the variable for the class rather than one for each instance of the class. It will, in effect, be global within that class. There will be one and only one copy of a class variable no matter how many instances of the class are created. The static keyword enables the implementation of the Singleton class.

Here is how it would be implemented in Java:

public class Singleton{  // methods and attributes for Singleton pattern  private Singleton() {}  static private Singleton _instance;  static public Singleton getInstance() {    if (_instance == null)       _instance = new Singleton();    return _instance;  }  // methods and attributes for global data}

Listing 1

Since there will be only one instance of the Singleton class, it needs to have control over its own creation. The constructor in Listing 1 has been declared private to prevent instantiations outside of the class. The class variable _instance is also declared private so that it cannot be accessed or modified by anything other than the Singleton class. The getInstance method is public and this is the only point of access for anyone wanting to make use of the Singleton.

The first time the getInstance() method is called, the instance of Singleton will be created. This process is referred to as Lazy Instantiation. Class variables are initialized when the class is first loaded and since there is no static initializer attached, _instance will have an initial value of null. When getInstance() is first called, _instance will be null so a new Singleton object will be created and assigned to it. For every subsequent call, _instance has a non-null value so a reference to the already created Singleton object will be returned.

Please note that the Singleton class cannot be subclassed or extended because the constructor is declared to be

private
. If subclassing is required, the access specifier of the constructor can be changed from private to
protected
. Unlike C++, where protected means granting access to only derived classes, Java's protected access specifier grants access to all classes with the same package in addition to the subclasses. Thus classes within the same package could have multiple instantiations of the Singleton class, which defeats the purpose of the pattern.

Singleton for Multi-threaded Uses

If multiple threads will be accessing the Singleton, there is a potential for multiple instantiations. A thread could be preempted while partway through the getInstance() method because the method is not synchronized. A second thread could then leapfrog the first by executing getInstance() before the first thread comes back and completes the method. The problem could be resolved by applying the synchronized specifier:

synchronized static public Singleton getInstance() { 

Listing 2

This solution shown in Listing 2 causes another problem for multi-threaded applications in that only one thread can be executing the method at a given time. Any threads waiting to get an instance of Singleton will be blocked until the first thread has exited the getInstance method. This results in slower application performance.

Fortunately all this unnecessary blocking can be avoided by applying the Double Checked Locking pattern as described by Mark Grand in his book Patterns in Java Volume 2.

Applying the Double Check Locking pattern makes a small but significant change to the getInstance() method, as shown in Listing 3.

public static Singleton getInstance() {  if (_instance == null) {    synchronized(Singleton.class) {      if (_instance == null)        _instance = new Singleton();    }  }  return _instance;}

Listing 3

The getInstance() method has been changed with the addition of a synchronized portion of code, or "critical section." This use of the synchronized keyword differs from Listing 2 where it was a method specifier and only allowed one concurrent access to the method. Here, the synchronized keyword attempts to gain an exclusive lock on the Singleton.class object. The critical section of code following is not executed until the lock is obtained, ensuring that no other threads can be executing the section at the same time.

The multiple instantiation problem has been solved in Listing 3 because of Double Check Locking. While it is still possible for a thread to be preempted after the first _instance comparison and be leapfrogged by another thread, the second _instance comparison within the critical section will allow such a thread to realize that the Singleton object has already been created. Every subsequent call to getInstance() will then bypass the critical section, resulting in no blocked threads.

Implementing Global Variables

Now that the infrastructure of the Singleton class has been developed, the global data can be implemented.

Global data should be declared to be private and getter and setter methods should be used for access. Declaring the data as a private and controlling access ensures it will not be changed accidentally or maliciously from outside the class. It also allows the Singleton to enforce error checking and control access.

Using a standard naming convention for getters and setters will make the code much more understandable. Setters, methods that set the value of a variable, should use the prefix

set
in the method name. Getters, methods that retrieve values, should use the prefix get in the method name. Getters that retrieve a Boolean value should use the prefix
is
in the method name.

Examples:

setEnabled()getName()isEnabled()

Using this naming convention, a global integer would be implemented as seen in Listing 4.

  // keep global data private  private int globalInteger;    public int getGlobalInteger() {     return globalInteger;   }    public void setGlobalInteger(int value) {    globalInteger = value;  }

Listing 4

An initGlobals() method can be used to do any required initialization of the global data at the time the Singleton is instantiated. An example of this is shown in Listing 5:

  private Singleton() { // private constructor    initGlobals();  }   // methods and attributes for global data    // constructor for global variables  private void initGlobals() {     globalInteger = 5;  }

Listing 5

Accessing the globalInteger from anywhere in your Java code can then be done in the following fashion:

Singleton.getInstance().getGlobalInteger();

Listing 6

Controlling access to the global variables allows for the implementation of calculated data. For example, if there was a counter that was used to generate unique IDs, then you wouldn't want a setter method and the getter might be synchronized, as shown in this example code:

  private void initGlobals() {     idCounter = 0;  }    private int idCounter;    synchronized public int getUniqueID() {     idCounter++;    return idCounter;   }

Listing 7

While the examples shown here all depict simple data being used globally, there is no reason why more complex structures can't be used as well. The Singleton class can be used to aggregate any number of objects.

Conclusion

With just a few lines of code, the Singleton pattern can be implemented in Java to provide a single point where all global data can be stored and accessed. Java is already an easy language for C++ developers to pick up, but mastering the Singleton pattern and using it to implement global data makes the transition easier than ever.

About the Author

With over thirteen years' experience in application development, Wiebe de Jong is a Web developer for IMRglobal Ltd in Vancouver, BC, Canada. He develops Internet and intranet applications for clients using Java, UML, and XML. He also teaches.






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel