1. An overview of the

In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. The concept is sometimes generalized to systems that operate more efficiently when only one object exists, or that restrict the instantiation to a certain number of objects. The term comes from the mathematical concept of a singleton. – wikipedia

Singleton: An object creation pattern that ensures that a class in a program has at most one instance and provides a global point of access to that instance.

The singleton pattern solves similar problems:

  • How can we ensure that there is only one instance of a class?
  • How can I easily access a unique instance of a class?
  • How does a class control its instantiation?
  • How do I limit the number of instances of a class?

Solution to singleton pattern:

  • To hide the class constructor, useprivateModifiers modify constructors.
  • Define a public static method (getInstance()), returns a unique static instance of this class.

2. Application scenarios

The singleton pattern can be used in the following scenarios:

  • Some management classes that ensure consistent access to resources.
  • Objects that take too much time or resources to create, but are often used.
  • Tool class object;
  • Objects that frequently access databases or files.

Android:

  • Context.getSystemService()

  • KeyguardUpdateMonitor.getInstance(mContext)

  • Calendar.getInstance()

  • .

Other:

  • Log Operations
  • File manager
  • The connection ruler for the database
  • .

3. Implementation method

3.1 the hungry

Hungry, so create an instance of the class directly when the class is loaded.

/** * Singleton class. Eagerly initialized static instance guarantees thread safety. */
public final class Singleton {

  /** * Private constructor so nobody can instantiate the class. */
  private Singleton(a) {}

  /** * Static to class instance of the class. */
  private static final Singleton INSTANCE = new Singleton();

  /**
   * To be called by user to obtain instance of the class.
   *
   * @return instance of the singleton.
   */
  public static Singleton getInstance(a) {
    returnINSTANCE; }}Copy the code

Advantages:

  • Multithreading safety

Disadvantages:

  • Memory is wasted. Instances are created as soon as the class is loaded, but memory is wasted if the program is not used for a particular run.

Summary:

  • Suitable for cases where singletons occupy small memory and will be used during initialization.

  • Not suitable: singletons occupy a large amount of memory, or they are only used in a specific scenario

3.2 LanHanShi

Lazy, hence the name, lazy, creating instances only when needed.

/** * Singleton class. Eagerly initialized static instance guarantees thread safety. */
public final class Singleton {

  /** * Private constructor so nobody can instantiate the class. */
  private Singleton(a) {}

  /** * Static to class instance of the class. */
  private static final Singleton INSTANCE = null;

  /**
   * To be called by user to obtain instance of the class.
   *
   * @return instance of the singleton.
   */
  public static Singleton getInstance(a) {
    if (INSTANCE == null){
        INSTANCE = new Singleton();
    }
    returnINSTANCE; }}Copy the code

Advantages:

  • Memory savings, since instances of this pattern are created when needed, can save memory if the program runs unused

Disadvantages:

  • Threads are unsafe, as follows
    Thread 1 Thread 2 INSTANCE
    public static Singleton getInstance() { null
    public static Singleton getInstance() { null
    if (INSTANCE == null){ null
    if (INSTANCE == null){ null
    INSTANCE = new Singleton(); object1
    return INSTANCE; object1
    INSTANCE = new Singleton(); object2
    return INSTANCE; object2

    Bad things happen, and here we return 2 different instances.

Summary:

  • Suitable for: single threaded, memory sensitive

  • Not for: multithreading

3.3 Thread-safe slob

/** * Thread-safe Singleton class. The instance is lazily initialized and thus needs synchronization * mechanism. * * Note: if created by reflection then a singleton will not be created but multiple options in the * same classloader */
public final class ThreadSafeLazyLoadedSingleton {

  private static ThreadSafeLazyLoadedSingleton instance;

  private ThreadSafeLazyLoadedSingleton(a) {
  // to prevent instantiating by Reflection call
    if(instance ! =null) {
        throw new IllegalStateException("Already initialized."); }}/** * The instance gets created only when it is called for first time. Lazy-loading */
  public static synchronized ThreadSafeLazyLoadedSingleton getInstance(a) {
    if (instance == null) {
        instance = new ThreadSafeLazyLoadedSingleton();
    }
    returninstance; }}Copy the code

Advantages:

  • Multithreading safety

Disadvantages:

  • Execution is inefficient, with each thread executing getInstance() synchronized whenever it wants to get an instance of the class. If you want to get an instance of the class, return it. Method synchronization efficiency is too low to improve.

Summary:

  • This method is not recommended. Other methods will be introduced later to ensure memory and multithreading security.

3.4 Double check for thread safety

/**
 * Double check locking
 * <p/>
 * http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
 * <p/>
 * Broken under Java 1.4.
 *
 * @author [email protected]
 */
public final class ThreadSafeDoubleCheckLocking {

  private static volatile ThreadSafeDoubleCheckLocking instance;

  /** * private constructor to prevent client from instantiating. */
  private ThreadSafeDoubleCheckLocking(a) {
    // to prevent instantiating by Reflection call
    if(instance ! =null) {
      throw new IllegalStateException("Already initialized."); }}/**
   * Public accessor.
   *
   * @return an instance of the class.
   */
  public static ThreadSafeDoubleCheckLocking getInstance(a) {
    // local variable increases performance by 25 percent
    // Joshua Bloch "Effective Java, Second Edition", p. 283-284
    
    ThreadSafeDoubleCheckLocking result = instance;
    // Check if singleton instance is initialized. If it is initialized then we can return the // instance.
    if (result == null) {
      // It is not initialized but we cannot be sure because some other thread might have // initialized it
      // in the meanwhile. So to make sure we need to lock on an object to get mutual exclusion.
      synchronized (ThreadSafeDoubleCheckLocking.class) {
        // Again assign the instance to local variable to check if it was initialized by some // other thread
        // while current thread was blocked to enter the locked zone. If it was initialized then // we can
        // return the previously created instance just like the previous null check.
        result = instance;
        if (result == null) {
          // The instance is still not initialized so we can safely (no other thread can enter // this zone)
          // create an instance and make it our singleton instance.
          instance = result = newThreadSafeDoubleCheckLocking(); }}}returnresult; }}Copy the code

Advantages:

  • Multithreading safety

Note:

  • Multithreaded security is not implemented under JDK 1.5

Summary:

  • You can use this method for both memory and multithreading safety.

3.5 Static inner Classes

public class Singleton {
    private Singleton(a) {}/** * Class level inner class, that is, static member inner class, the inner class instance is not bound to the outer class instance *, and is only loaded when called, thus implementing lazy loading. * /
    public static Singleton getInstance(a) {
        return SingletonLazyHolder.instance;
    }

    private static class SingletonLazyHolder {
        /** * static initializer, thread safe by JVM */
        private final static Singleton instance = newSingleton(); }}Copy the code

Advantages:

  • Multithreading safety

Note:

  • Multithreaded security is not implemented under JDK 1.5

Summary:

  • You can use this method for both memory and multithreading safety.

3.6 the enumeration

public enum EnumSingleton {

  INSTANCE;

  @Override
  public String toString(a) {
    return getDeclaringClass().getCanonicalName() + "@"+ hashCode(); }}Copy the code

Summary:

  • You can use this method for both memory and multithreading safety. This is also the recommended approach for Effective Java. Note that enumerations were added in JDK 1.5 as well.

4. To summarize

The singleton occupies a small amount of memory and will be used during initialization – method 3.1 is recommended

Multithreading security and high memory usage. Recommended 3.4.3.5,3.6. Pay attention to the JDK version when using it. I recommend using 3.4.3.5.

5.Android code examples

5.1 Dialer, using method 3.2

packages/apps/Dialer/java/com/android/incallui/InCallPresenter.java

private static InCallPresenter sInCallPresenter;
/** Inaccessible constructor. Must use getRunningInstance() to get this singleton. */
@VisibleForTesting
InCallPresenter() {}
public static synchronized InCallPresenter getInstance(a) {
    if (sInCallPresenter == null) {
      sInCallPresenter = new InCallPresenter();
    }
    return sInCallPresenter;
}

// Other irrelevant code omitted
Copy the code

5.2 Email, method 3.5

packages/apps/Dialer/java/com/android/incallui/InCallPresenter.java

public class NotificationControllerCreatorHolder {
    private static NotificationControllerCreator sCreator =
            new NotificationControllerCreator() {
                @Override
                public NotificationController getInstance(Context context){
                    return null; }};public static void setNotificationControllerCreator( NotificationControllerCreator creator) {
        sCreator = creator;
    }

    public static NotificationControllerCreator getNotificationControllerCreator(a) {
        return sCreator;
    }

    public static NotificationController getInstance(Context context) {
        returngetNotificationControllerCreator().getInstance(context); }}Copy the code

If you are interested, you can look for cases yourself.

6. Singleton with parameters

There are many singleton scenarios on Android that require Context parameters. Take a look at an example of Android source code:

packages/apps/Email/src/com/android/email/EmailNotificationController.java

    private static EmailNotificationController sInstance;
    /** Singleton access */
    public static synchronized EmailNotificationController getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new EmailNotificationController(context, Clock.INSTANCE);
        }
        return sInstance;
    }
Copy the code

If the pass parameter is sensitive and needs to be replaced, it needs to be handled:

public final class Singleton {

    private Context context;
    private static volatile Singleton instance;

    private Singleton(Context context) {
        this.context = context;
        if(instance ! =null) {
            throw new IllegalStateException("Already initialized."); }}public static Singleton getInstance(Context context) {
        Singleton result = instance;
        if (result == null) {
            synchronized (Singleton.class) {
                result = instance;
                if (result == null) {
                    instance = result = newSingleton(context); }}// Pay attention to reassignment here
            instance.context = context;
        }
        returnresult; }}Copy the code

thanks

  1. Initialization-on-demand holder idiom
  2. Singleton pattern
  3. Head First design pattern
  4. java-design-patterns