理解单例模式


title: “理解单例模式”

url: “https://wsk1103.github.io/

tags:

  • 设计模式

是什么

Ensure a class only has one instance, and provide a global point of access to it.

确保一个类只有一个实例,并且提供一个全局的方法来访问这个类。

单例模式的实现
  • 饿汉式
  • 懒汉式
  • 静态内部类
  • 枚举

优缺点

优点:

全局提供一个类的实例,防止一个类被重复实例。

缺点

类内的全局变量的使用涉及到非线程安全。

饿汉式

public class Singleton {  
     private static Singleton instance = new Singleton();  
     private Singleton (){
     }
     public static Singleton getInstance() {  
        return instance;  
     }  
 } 

在类的加载的时候就已经进行了初始化,所以是线程安全的,但是类的加载会影响程序的启动时间。

懒汉式

非线程安全
public class Singleton {
    //私有构造函数
    private Singleton() {}  
    //单例对象
    private static Singleton instance = null;  
    //静态工厂方法
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

当多个进程同时来调用该方法时:假如A,B线程同时来到了 if 判断语句这里,同时判断为 true ,那么就获得了2个实例了。

当想要获取对应的单例时,再实例化该类,从而不再影响程序的启动。

线程安全

双重检验锁

public class Singleton {
    //私有构造函数
    private Singleton() {} 
    //单例对象,使用 volatile 关键字禁止指令重排序
    private volatile static Singleton instance = null; 
    //静态工厂方法
    public static Singleton getInstance() {
        //双重检测机制
        if (instance == null) {      
            //同步锁
             synchronized (Singleton.class){  
                //双重检测机制
                if (instance == null) {     
                    instance = new Singleton();
                }
            }
         }
        return instance;
    }
}

注意在声明 单例 的时候,使用 volatile 关键字禁止指令重排序。

静态内部类

public class Singleton { 
    private Singleton(){
    }
    public static Singleton getInstance(){  
        return SingletonHolder.instance;  
    }  
    private static class SingletonHolder {  
        private static final Singleton instance = new Singleton();  
    }  
} 

第一次加载 Singleton 类时并不会初始化 instance ,只有第一次调用 getInstance() 方法时虚拟机加载 SingletonHolder 并初始化instance ,这样不仅能确保线程安全也能保证 Singleton 类的唯一性。

枚举

public enum Singleton {  
     INSTANCE;  
     public void doSomeThing() {  
     }  
 } 

枚举声明的单例是线程安全的,在程序启动的时候就会加载该类。 枚举 声明的类不会因为反序列化或者反射就能获得第二个该类的实例,但是其他的几种模式会。

反射打破单例

//获得构造器
Constructor con = Singleton.class.getDeclaredConstructor();
//设置为可访问
con.setAccessible(true);
//构造两个不同的对象
Singleton singleton1 = (Singleton)con.newInstance();
Singleton singleton2 = (Singleton)con.newInstance();
//验证是否是不同对象
System.out.println(singleton1 == singleton2);
注意
  1. 使用枚举实现的单例模式,不但可以防止利用反射强行构建单例对象,而且可以在枚举类对象被反序列化的时候,保证反序列的返回结果是同一对象。
  2. 对于其他方式实现的单例模式,如果既想要做到可序列化,又想要反序列化为同一对象,则必须实现 readResolve 方法。
单例模式是否线程安全是否懒加载是否防止反射,反序列化构建
饿汉式
双重检验锁
静态内部类
枚举
java中的应用
  • java.lang.Runtime#getRuntime()
  • java.awt.Desktop#getDesktop()
  • java.lang.System#getSecurityManager()

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值