单例模式的实现方式总结
一、饿汉式
饿汉式----静态常量
//饿汉式-静态常量方式
class Singleton{
//私有话构造器
private Singleton(){}
//给定一个私有的实例
private static final Singleton singleton=new Singleton();
//对外暴露一个接口
public static Singleton getInstance(){
return singleton;
}
}
饿汉式---静态代码块方式
//饿汉式-静态代码块方式
class Singleton{
private Singleton(){}
private static final Singleton singleton;
static {
singleton=new Singleton();
}
public static Singleton getInstance(){
return singleton;
}
}
二、懒汉式
//懒汉式 --线程不安全 在单线程下使用,实现懒加载
class Singleton{
private Singleton(){}
private static Singleton singleton;
public static Singleton getInstance(){
if(singleton==null){
singleton= new Singleton();
}
return singleton;
}
}
三、双重检测锁机制
//双层检测所机制 线程安全,效率高,懒加载
class Singleton{
private Singleton(){}
private static Singleton singleton; //加volatile禁止指令重排
public static Singleton getInstance(){
if(singleton==null){
synchronized (Singleton.class){
if(singleton==null){
singleton=new Singleton();//可能会发生指令重排,造成空指针异常
}
}
}
return singleton;
}
}
对singleton=new Singleton()这行代码进行分析,其实有三步:
-
在堆中申请一块内存地址
-
初始化内存对象singleton
-
将内存地址赋值给对象
但在实际运行时,可能第二步和第三步的顺序发生变化,因为第二步和第三步都是依托于第一步的结果的,所以第一步不会重排。
在多线程下,如果线程一进来执行完第一步再执行第三步时,此时线程二进来了,返回了对象。此时对象并未初始化,访问时就可能造成空指针异常。解决方案:加Volatile,禁止指令重排。
四、枚举方式
更简洁,自动支持序列化机制,绝对防止多次实例化。
//枚举方式
enum Singleton{
INSTANCE;
}
验证
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
Singleton instance1 = Singleton.getInstance();
System.out.println(instance == instance1);
//Singleton singleton=Singleton.INSTANCE;
}

浙公网安备 33010602011771号