Lecture 11 Singleton

Joseph Haugh

University of New Mexico

Free Recall

  • Get out a sheet of paper or open a text editor
  • For 2 minutes write down whatever comes to mind about the last class
    • This could be topics you learned
    • Questions you had
    • Connections you made

Global State??

The Notion of a Singleton

  • Sometimes we may need one instance of an object:
    • Thread pools, caches, dialog boxes, logging objects, device drivers, etc.
  • In many of these cases, instantiating more than one of such objects creates all kinds of problems
    • incorrect program behavior
    • resource overuse
    • inconsistent results

Towards a Singleton

  • In Java, how do you create a single object?

  • new MyClass()

  • And if you call that a second time?

  • You get a second, distinct object

  • How could you prevent such instantiation?

    public class MyClass {
        private MyClass() {}
    }
  • Who can use such a private constructor?

  • Only code within MyClass

The Next Step

  • How can you get access to code within MyClass if you can’t instantiate it?

  • What about like this?

    public class MyClass {
        public static MyClass getInstance() {
            // ...
        }
    }
  • How would you call that?

  • MyClass.getInstance();

  • How would you fill out the implementation to make sure that only a single instance of MyClass is ever created?

The Classic Singleton

public class Singleton {
    private static Singleton uniqueInstance;

    // additional instance variables

    private Singleton() {}

    public static Singleton getInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }

    // additional methods
}

The Singleton Pattern

  • The Singleton Pattern ensures a class has only one instance and provides a global point of access to that instance.

The Singleton Class Diagram

We have a problem. . .

  • The Singleton pattern, as we have implemented it, is not thread safe
  • When multiple threads invoke the getInstance() method, multiple instances of the object may be created!
    • Thread1 might execute if (uniqueInstance == null) and see its true
    • Thread2 then executes if (uniqueInstance == null) and see its true
    • Thread1 creates an instance
    • Thread2 creates an instance

Possible solution

  • One solution is to use eager instantiation instead of lazy instantiation

    public class Singleton {
        private static Singleton uniqueInstance = new Singleton();
    
        private Singleton() {}
    
        public static Singleton getInstance() {
            return uniqueInstance;
        }
    }
  • We will need to return to this type of problem when we study concurrent programming!

Public Field Approach

  • We can also opt to just make the singleton instance a public static final field:

    public class Singleton {
        public static final Singleton INSTANCE = new Singleton();
    
        private Singleton() {}
    }
  • This is even simpler than having a static method

  • The only downside to this vs a static method is you cannot change your mind about being a Singleton!

    • Since user will be relying on INSTANCE as part of the API we cannot remove it
    • Whereas, we could change getInstance to return multiple instances

Is Anything Truly Private?

What I am about to show must be only utilized in the most dire circumstances

Reflection

  • Reflection allows us to manipulate boundaries of the language we are normally not allowed to cross
  • This includes the scoping rules enforced by public, private, and protected
  • Here is some code to break our old singleton:
// Get the constructor reflectively, or in other words at runtime
Constructor<SingletonPublicField> constructor = 
    SingletonPublicField.class.getDeclaredConstructor();
// Make it public
constructor.setAccessible(true);
// Get the supposed only instance
SingletonPublicField unique1 = SingletonPublicField.INSTANCE;
// Then create another one
SingletonPublicField unique2 = constructor.newInstance();
// Show they are not the same
System.out.println("unique1 != unique2 = " + (unique1 != unique2)); // true

Unbreakable Singleton

  • Luckily, Java gives a way to avoid this attack entirely!
  • We can use enums to create our singleton
  • Recall, that enums in Java are implemented as classes with a limited number of instances (the members of the enum)
  • Perfect for creating a singleton

Enum Singleton

public enum Singleton {
    INSTANCE
}
  • All the same advantages as the public field approach
  • Robust to reflection
  • Same downside of public field as well, you cannot change your mind

Some Questions

  • What’s the difference between a Singleton and a class in which all of the methods and variables are static?
    • Using the Singleton pattern instead allows for complex initialization (especially if that initialization involves other classes and objects)
    • Without the Singleton pattern, you can still implement these things, but the result are common “order of initialization” bugs that are hard to pin down
  • Why can’t you subclass a Singleton?
    • You can’t extend a class with a private constructor
    • All of the derived classes share the same static variable “instance”

When To Use a Singleton?

  • Very few problems warrant the use of singletons If your problem has the following three properties then you MAY want to use singletons
      1. There can only be one object
      1. Object controls concurrent access to a shared resource (i.e. database)
      1. Access to the resource will be necessary in separate parts of the system
  • Another good rule of thumb is if you are only sending data to a shared object and no data is coming back out then a singleton might be appropriate (i.e. logging)

Code