DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Singleton: 6 Ways To Write and Use in Java Programming
  • Java String: A Complete Guide With Examples
  • Generics in Java and Their Implementation
  • How to Estimate Object Memory Allocation in Java

Trending

  • How To Replicate Oracle Data to BigQuery With Google Cloud Datastream
  • Why We Still Struggle With Manual Test Execution in 2025
  • Scalable System Design: Core Concepts for Building Reliable Software
  • Stateless vs Stateful Stream Processing With Kafka Streams and Apache Flink
  1. DZone
  2. Coding
  3. Languages
  4. Singletons: Bill Pugh Solution or Enum

Singletons: Bill Pugh Solution or Enum

There is a variety of approaches you can take with Singleton patterns. Here, we pit Bill Pugh's solution against the handy Enum singleton.

By 
Harinath Kuntamukkala user avatar
Harinath Kuntamukkala
·
Updated Oct. 09, 17 · Tutorial
Likes (11)
Comment
Save
Tweet
Share
45.1K Views

Join the DZone community and get the full member experience.

Join For Free

A singleton class ensures that only one instance of that class is created. To ensure the point of access, the class controls the instantiation of its object. Singleton classes are found in many places in the JDK, such as java.lang.Runtime.

The Singleton class offers two things: one and only one instance of the class, and a global single point of access to that object

Implementation

To implement a Singleton pattern, we have different approaches — but all of them have the following common concepts.

  • Private constructor to prevent instantiation of the class from other classes.
  • Private static variable of the same class that is the only instance of the class.
  • Public static method that returns the instance of the class. This is the global access point for the outside world to get the instance of the singleton class.
//Logger class must be instantiated one and only once in the application; it is to ensure that the
//application makes use of that same logger instance
public class Logger {

    //declare the constructor private to prevent clients
    //from instantiating an object of this class directly
    private Logger() {}

    //by default, this field is initialized to null
    //the static method to be used by clients to get the instance of the Logger class
    private static Logger myInstance;

    public static Logger getInstance() {
        if (myInstance == null) {
            //this is the first time this method is called,
            //and that's why myInstance is null
            myInstance = new Logger();
        }

        //return the same object reference any time and
        //every time getInstance is called
        return myInstance;
    }

    //Other methods
}


Can we ensure that our Singleton is indeed a Singleton? We will discuss that later in the article.

Different Approaches

  • Eager initialization: instance of a class is created long before it is actually required
  • Lazy initialization: instance of a class is created when the client sends a request
  • Static block initialization: is similar to eager initialization, except that the instance of the class is created in the static block that provides the option for exception handling
  • Thread safe singleton: is to make the global access method is synchronized so that only one thread can execute this method at a time
  • Bill Pugh singleton: implementation using the static inner helper class. Static inner classes are not loaded into memory until their getInstance() methods are called
  • Enum singleton: provides implicit support for thread safety and only one instance is guaranteed

Eager initialization and lazy initialization work fine in a single-threaded environment. However, they won't be suitable for multi-threaded environments.

Static block initialization has one drawback: If we have a class with three static fields and the application needs to access only one, for which instance creation is not required at all, we still have one instance created — whether we require it or not.

A thread safe singleton works fine in multi-threaded environments but reduces performance because of the cost associated with the synchronized method.

To overcome the issue of synchronization, Bill Pugh came up with his implementation using the static inner helper class. The static inner class is not loaded into memory until its getInstance() method is called.

Meanwhile, Enum singletons provide implicit support for thread safety and only one instance is guaranteed, as per the Javadocs.

So, for this article, we're going to focus on the Bill Pugh approach and Enum singletons. Out of all other approaches, these two work well in single- and multi-threaded environments without a performance impact.

Bill Pugh Singleton

A Bill Pugh Singleton is based on the “initialization on demand holder” idiom. This idiom uses inner classes and does not use any synchronization construct. It uses static blocks, but in a different way — and suggests using static inner classes.

We will rewrite the above Logger program using the Bill Pugh approach here.

public class Logger {
    private Logger() {
        // private constructor
    }

    // static inner class - inner classes are not loaded until they are
    // referenced.
    private static class LoggerHolder {
        private static Logger logger = new Logger();
    }
    // global access point
    public static Logger getInstance() {
        return LoggerHolder.logger;
    }

    //Other methods
}


The Bill Pugh Singleton is the best approach so far, but it can be easily destroyed with the use of Java reflection.

public class LoggerReflection {

    public static void main(String[] args) {
        Logger instance1 = Logger.getInstance();
        Logger instance2 = null;
        try {
            Constructor[] cstr = Logger.class.getDeclaredConstructors();
            for (Constructor constructor: cstr) {
                //Setting constructor accessible
                constructor.setAccessible(true);
                instance2
                    = (Logger) constructor.newInstance();
                break;
            }
        } catch (Exception e) {
            System.out.println(e);
        }
        System.out.println(instance1.hashCode());
        System.out.println(instance2.hashCode());
    }


When you run the above class, you will notice that the hashCode of both the instances is not same, which destroys the singleton pattern.

Enum Singleton

To overcome this situation with Reflection, Joshua Bloch suggests the use of Enum to implement the Singleton design pattern, as Java ensures that any Enum value is instantiated only once in a Java program. However, the obvious drawback is that we cannot have lazy loading in Enum.

So, the Logger class will look like this using an Enum Singleton.

public enum Logger {
    INSTANCE;

    //other methods
}


To get the instance client, we need to call Logger.INSTANCE.

What if we need serialization for this Singleton?

If the Singleton class implements java.io.Serializable and a singleton object is serialized, then deserialized more than once, there will be multiple instances of the Singleton.

In order to avoid the serialization issue, implement a readResolve() method in the Logger Singleton class as below:

public class Logger implements Serializable {
    //other code related to Singleton
    //call this method immediately after De-serialization
    //it returns an instance of singleton
    protected Object readResolve() {
        return getInstance();
    }
}


Conclusion

We have discussed different approaches of creating a Singleton class and mainly focused on the Bill Pugh and Enum approaches. Out of these two, I feel the Enum pattern is better, as this approach is functionally equivalent to the public field approach, except that it is more concise, provides the serialization machinery for free, and provides an ironclad guarantee against multiple instantiations, even in the face of sophisticated serialization or reflection attacks.

Thank you.

Thread safety Blocks Serialization Java (programming language) Lazy loading Lazy initialization Implementation Object (computer science) Memory (storage engine)

Published at DZone with permission of Harinath Kuntamukkala. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Singleton: 6 Ways To Write and Use in Java Programming
  • Java String: A Complete Guide With Examples
  • Generics in Java and Their Implementation
  • How to Estimate Object Memory Allocation in Java

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!