单例设计模式
单例设计模式
单例模式(Singleton Pattern)是Java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供例一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供类一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
1. 单例模式的结构
单例模式主要有以下角色:
- 单例类。只能创建一个实例的类
- 访问类。使用单例类
2. 单例模式的实现
单例设计模式分类两种:
饿汉式:类加载就会导致该单实例对象被创建 懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会被创建
2.1 饿汉式:
/**
* 饿汉式
* 在静态代码块中创建该类对象
*/
public class Singleton {
// 私有构造方法
private Singleton() {}
// 在成员位置创建该类的对象
private static Singleton instance;
static {
instance = new Singleton();
}
// 对外提供静态方法获取该对象
public static Singleton getInstance() {
return instance;
}
}
饿汉式实现单例模式存在内存浪费的问题。
2.2 懒汉式-方式1(双重检查锁模式)
懒汉式实现单例模式在多线程情况下会有线程不安全的问题,以下示例使用双重检查锁模式
实现。
/**
* 双重检查模式
*/
public class Singleton {
// 私有构造方法
private Singleton() {}
private static Singleton instance;
// 对外提供静态方法获取该对象
publice static Singleton getInstance() {
// 第一次判断,如果instance不为null,不进入抢锁阶段,直接返回实例
if(instance == null) {
synchronized (Singleton.class) {
// 第二次判断
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
双重检查锁模式是一种非常好的单例实现模式,解决例单例、性能、线程安全问题,但是在多线程情况下,可能会出现空指针问题,出现问题的原因是JVM在实例化对象的时候会进行优化和指令重排序操作。要解决双重检查锁模式带来空指针异常的问题,只需要使用volatile
关键字修饰实例变量即可,volatile
关键字可以保证可见性和有序性。
2.3 懒汉式-方式2(静态内部类方式)
静态内部类单例模式中实例由内部类创建,由于JVM在加载外部类过程中,是不会加载静态内部类的,只有内部类的属性/方法被调用时才会被加载,并初始化其静态属性。静态属性由于被static
修饰,保证只被实例化一次,并且严格保证实例化顺序。
/**
*静态内部类方式
*/
public class Singleton {
// 私有构造方法
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
// 对外提供静态方法获取该对象
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
第一次加载Singleton类时不会去初始化INSTANCE,只 有第一次调用getInstance,虚拟机加载SingletonHolder并初始化INSTANCE,这样不仅能确保线程安全,也能保证Singleton类的唯一性。\
静态内部类单例模式是一种优秀的单例模式,是开源项目中比较常见的一种单例模式。在没有加任何锁的情况下,保证了多线程下的安全,并且没有任何性能影响和空间的浪费。