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, use
private
Modifiers 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
- Initialization-on-demand holder idiom
- Singleton pattern
- Head First design pattern
- java-design-patterns