单例模式的定义
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
单例模式的使用场景
确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源。
实现单例模式主要的关键点
(1)构造函数不对外开放,一般为private;
(2)通过一个公开的静态方法或者枚举返回单例类对象;
(3)确保单例类对象有且只有一个,尤其是在多线程环境下;
(4)确保单例类对象在反序列化时不会重新构建对象。
单例类的五种实现方式(这里只展示五种)
- (1)饿汉式
public class Singleton {
private static Singleton mInstance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return mInstance;
}
}
饿汉式特点:直接new一个单例类的实例对象,在使用时直接获取。
- (2)懒汉式
public class Singleton {
private static Singleton mInstance = null;
private Singleton(){};
public static synchronized Singleton getInstance(){
if(mInstance==null){
mInstance = new Singleton();
}
return mInstance;
}
}
懒汉式特点:懒汉式的优点是单例只在使用时才会被实例化,在一定程度上节约了资源;缺点是第一次加载时需要及时进行实例化,反应稍慢,最大的问题是每次调用getInstance方法都进行同步,造成不必要的同步开销。
- (3)Double Check Lock(DCL,双重检查锁)实现单例
public class Singleton {
private volatile static Singleton mInstance = null;
private Singleton(){};
public static Singleton getInstance(){
if(mInstance==null){//避免不必要的同步
synchronized(Singleton.class){
if(mInstance==null){//获取锁之后,判断在mInstance为null的情况下实例化
mInstance = new Singleton();
}
}
}
return mInstance;
}
}
volatile关键字是jdk1.5之后添加的,这样定义的对象在多线程下每次都是从主内存(进程内存)中去获取最新的实例(因为其他线程可能有修改了)
DCL实现单例特点:优点是资源利用率高,第一次执行getInstance时单例对象才会被实例化,效率高;缺点是第一次加载时反应稍慢,由于java内存模型的原因偶尔会失败(并发场景十分复杂或者低于JDK6版本使用)
-
(4)静态内部类实现单例
《Java并发编程实践》一书中指出DCL虽然解决了很多问题,但是仍然存在双重检查锁定失效,并建议使用静态内部类来实现单例模式:
public class Singleton {
private Singleton(){};
public static Singleton getInstance(){
return SingletonHolder.mInstance;
}
private static class SingletonHolder{
private static final Singleton mInstance = new Singleton();
}
}
非静态内部类(对象级内部类)必须绑定在外部类对象实例上,而静态内部类(类级内部类)不存在依赖,和其他外部类一样,在第一次使用时装载,直接创建。
具体来说,当第一次加载Singleton类时并不会初始化mInstance,只有在第一次调用Singleton的getInstance方法时才会导致mInstance被初始化(第一次调用getInstance方法会导致虚拟机加载SingletonHolder类,加载类时会初始化静态域,也就是说会初始化mInstance),这种方式不仅能够确保线程安全,也能够保证单例对象的唯一性,同时也延迟了单例的实例化(在使用时采取初始化单例对象)
-
(5)枚举单例
上述几个方式在反序列化的时候会重新创建对象,但是默认的枚举实例的创建是线程安全,并且在任何情况下都是单例。
在Android中的单例模式
Android的系统核心服务都是以单例形式存在的,比如ActivityManagerService、WindowManagerService、LayoutInflater等等。
总结
单例模式中DCL双重检查锁定实现单例和静态内部类实现单例两种方式使用最多,在这些实现方式中,我们不难看出,Java基础的重要性(Java内存模型、原子操作、类加载等),有两本书还是需要去看一看《深入理解java虚拟机》 《Java并发编程实践》
网友评论