一、定义
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
二。使用场景
当对象需要消耗的资源过多(如访问Io、数据库等),避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一个。
三、实现方法
(1)饿汉单例模式
依靠静态对象的初始化实现单例
public class Singleton{
private static Singleton mInstance = new Singleton();
private Singleton() {}
public static synchronized Singleton getInstance(){
return mInstance;
}
}
复制代码
(2)懒汉单例模式
第一次调用getInstance()后,单例对象就会被实例化。但每次调用getInstance()方法时都需要进行同步,会造成不必要的消耗。
对于不频繁调用getInstance()的情况下,可以适用。
public class Singleton{
private static Singleton mInstance;
private Singleton() {}
public static synchronized Singleton getInstance(){
if( mInstance == null){
mInstance = new Singleton();
}
return mInstance;
}
}
复制代码
(3) Double Check Lock(DCL) 实现单例
public class Singleton{
private volatile static Singleton mInstance;
private Singleton() {}
public static Singleton getInstance(){
if( mInstance == null){
synchronized(Singleton.class){
if( mInstance == null){
mInstance = new Singleton();
}
}
}
return mInstance;
}
}
复制代码
进行两次判空,第一次判断主要避免不必要的同步,第二次判断主要为了在同步情况下确认单例仍为空时,进行初始化。
volatile关键字的作用:
1、防止重排序
new对象时,会进行三件事件:
(1)、给Singleton的实例分配内存;
(2)、调用Singleton()的构造方法,初始化成员变量。
(3)、将mInstance对象指向分配的内存空间。
而在JVM中(2)和(3)的顺序是无法被保证的,只能通过volalite保证其有序性。
2、保证线程的可见性。
(4) 静态内部类单例模型
依靠静态内部类被使用时才被JVM加载的原理。
public class Singleton{
private Singleton{}
public static Singleton getInstance(){
return SingletonHolder.mInstance;
}
//静态内部类
private static class SingletonHolder{
private static final Singleton mInstance = new Singleton();
}
}
复制代码
静态内部类和非静态内部类加载时机的区别:
非静态内部类,一定需要外部类实例化后才会被加载。
静态内部类的加载不需要依附外部类,在使用时才加载进。
(5) 使用容器实现单例。
将多种单例类型注入到一个统一的管理类中,使用时根据key获取对应的单例对象。
public class SingletonManager{
private static Map<String,Object> objMap = new HashMap<String,Object>();
private SingletonManager{}
public static void registerService(String key,Object instance){
if(!object.containsKey(key)){
objMap.put(key,instance);
}
}
public static Object getService(String key){
return objMap.get(key);
}
}
复制代码
(6) 枚举单例
枚举类型可以定义自己的方法和自己的变量,而且枚举实例的创建是线程安全的,并且任何情况下都是单例。
public enum SingletonEnum{
INSTANCE;
public void doSomething(){
System.out.println("do ");
}
}
复制代码