【设计模式(三)】创建型模式--单例模式
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是“将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。
饿汉式
类加载就会导致该单实例对象被创建
/**
* 饿汉式
* 静态变量创建类的对象
*/
public class Singleton {
//私有构造方法
private Singleton() {}
//在成员位置创建该类的对象
private static Singleton instance = new Singleton();
//对外提供静态方法获取该对象
public static Singleton getInstance() {
return instance;
}
}
懒汉式
类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建
需要加锁保证线程安全。
public class Singleton{
private static Singleton INSTANCE;
private Singleton(){}
public static synchronized Singleton getINSTANCE(){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
懒汉式--双重验证实现
JVM在实例化对象的时候会进行优化和指令重排序操作
singleton = new Singleton();
该语句非原子操作,实际是三个步骤。
1.给singleton分配内存;
2.调用 Singleton 的构造函数来初始化成员变量;
3.将给singleton对象指向分配的内存空间(此时singleton才不为null);
执行命令时虚拟机可能会对以上3个步骤交换位置 最后可能是132这种 分配内存并修改指针后未初始化 多线程获取时可能会出现问题。
当线程A进入同步方法执行singleton = new Singleton();代码时,恰好这三个步骤重排序后为1 3 2,那么步骤3执行后singleton已经不为null,但是未执行步骤2,singleton对象初始化不完全,此时线程B执行getInstance()方法,第一步判断时singleton不为null,则直接将未完全初始化的singleton对象返回了。
public class Singleton{
private static volatile Singleton INSTANCE;
private Singleton(){}
public static synchronized Singleton getINSTANCE(){
if(INSTANCE == null){
synchronized (Singleton.class){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
静态内部类
加载类时并不会加载静态内部类,只有第一次使用它时才加载。
public class Singleton{
private Singleton(){}
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getINSTANCE(){
return SingletonHolder.INSTANCE;
}
}
枚举
枚举类实现单例模式是极力推荐的单例实现模式,因为枚举类型是线程安全的,并且只会装载一次,设计者充分的利用了枚举的这个特性来实现单例模式,枚举的写法非常简单,而且枚举类型是所用单例实现中唯一一种不会被破坏的单例实现模式。
public enum Singleton{
INSTANCE
}