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. - wikipediahtml
单例模式:是一种对象建立型模式,用来确保程序中一个类最多只有一个实例,并提供访问这个实例的全局点。java
单例模式解决如下相似问题:android
单例模式的解决方案:git
private
修饰符修饰构造方法.getInstance()
) ,返回这个类惟一静态实例。如下场景可以使用单例模式:github
Android:数据库
Context.getSystemService()设计模式
KeyguardUpdateMonitor.getInstance(mContext)安全
Calendar.getInstance()多线程
....app
其余:
饿汉式,故名思议,很饿,因此在类加载的时候就直接建立类的实例。
/** * Singleton class. Eagerly initialized static instance guarantees thread safety. */
public final class Singleton {
/** * Private constructor so nobody can instantiate the class. */
private Singleton() {}
/** * 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() {
return INSTANCE;
}
}
复制代码
优势:
缺点:
小结:
适合:单例占用内存比较小,初始化时就会被用到的状况。
不适合:单例占用的内存比较大,或单例只是在某个特定场景下才会用到
懒汉式,故名思议,很懒,须要用的时候才建立实例。
/** * Singleton class. Eagerly initialized static instance guarantees thread safety. */
public final class Singleton {
/** * Private constructor so nobody can instantiate the class. */
private Singleton() {}
/** * 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() {
if (INSTANCE == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
复制代码
优势:
缺点:
线程1 | 线程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 |
小结:
适合:单线程,内存敏感的
不适合:多线程
/** * 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() {
// 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() {
if (instance == null) {
instance = new ThreadSafeLazyLoadedSingleton();
}
return instance;
}
}
复制代码
优势:
缺点:
小结:
/** * Double check locking * <p/> * http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html * <p/> * Broken under Java 1.4. * * @author mortezaadi@gmail.com */
public final class ThreadSafeDoubleCheckLocking {
private static volatile ThreadSafeDoubleCheckLocking instance;
/** * private constructor to prevent client from instantiating. */
private ThreadSafeDoubleCheckLocking() {
// 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() {
// 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 = new ThreadSafeDoubleCheckLocking();
}
}
}
return result;
}
}
复制代码
优势:
注意点:
小结:
public class Singleton {
private Singleton() {
}
/** * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 * 没有绑定关系,并且只有被调用到时才会装载,从而实现了延迟加载。 */
public static Singleton getInstance() {
return SingletonLazyHolder.instance;
}
private static class SingletonLazyHolder {
/** * 静态初始化器,由JVM来保证线程安全 */
private final static Singleton instance = new Singleton();
}
}
复制代码
优势:
注意点:
小结:
public enum EnumSingleton {
INSTANCE;
@Override
public String toString() {
return getDeclaringClass().getCanonicalName() + "@" + hashCode();
}
}
复制代码
小结:
单例占用内存比较小,初始化时就会被用到的状况 - 推荐使用方法 3.1
多线程安全和内存占用大,特定场景下采用,推荐使用方法 3.4.3.5,3.6. 使用时注意jdk的版本。我的推荐使用 3.4.3.5。
5.1 Dialer,使用方法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() {
if (sInCallPresenter == null) {
sInCallPresenter = new InCallPresenter();
}
return sInCallPresenter;
}
//其余无关代码省略
复制代码
5.2 Email,使用方法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() {
return sCreator;
}
public static NotificationController getInstance(Context context) {
return getNotificationControllerCreator().getInstance(context);
}
}
复制代码
有兴趣的能够本身再找找案例看看。
android上有不少须要Context参数的单例场景。先不要急,看看Android源码的实例:
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;
}
复制代码
其实也很简单吗,可是这里面有个小问题,若是传递参数是敏感的,是须要替换的,那就须要在处理一下:
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 = new Singleton(context);
}
}
//这里要注意从新赋值
instance.context = context;
}
return result;
}
}
复制代码