一、定义
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
- 单例类只能有一个实例
- 单例类必须自己创建自己的唯一实例
- 单例类必须为其他所有对象提供该这个实例
二、作用
保证一个类只有一个实例,并提供一个唯一的全局的访问点。主要解决了类的实例被不断地实例和销毁的问题。
三、设计类图
四、懒汉式(线程不安全)
public class Singleton {
private static Singleton instance;
//构造函数私有化
private Singleton (){}
public static Singleton getInstance() {
//如果对象为空 则新建该对象
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
线程不安全,延迟初始化。
五、懒汉式(线程安全)
public class Singleton {
private static Singleton instance;
private Singleton (){}
//添加synchronzied同步锁
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
通过加锁synchronized实现线程安全,但执行效率不高。
六、饿汉式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
线程安全,比较常用,但容易产生垃圾,因为一开始就初始化。
七、双重锁检查
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
线程安全,延迟初始化。这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
双重检查模式,进行了两次的判断,第一次是为了避免不要的实例,第二次是为了进行同步,避免多线程问题。由于singleton=new Singleton()
对象的创建在JVM中可能会进行重排序,在多线程访问下存在风险,使用volatile
修饰signleton
实例变量有效,解决该问题。
八、静态内部类单例模式
public class Singleton {
private Singleton(){
}
public static Singleton getInstance(){
//访问静态内部类的实例对象
return Inner.instance;
}
private static class Inner {
private static final Singleton instance = new Singleton();
}
}
只有第一次调用getInstance方法时,虚拟机才加载 Inner 并初始化instance ,只有一个线程可以获得对象的初始化锁,其他线程无法进行初始化,保证对象的唯一性。目前此方式是所有单例模式中最推荐的模式,但具体还是根据项目选择。
九、枚举单例模式
public enum Singleton {
INSTANCE;
}
默认枚举实例的创建是线程安全的,并且在任何情况下都是单例。实际上
- 枚举类隐藏了私有的构造器。
- 枚举类的域 是相应类型的一个实例对象
那么枚举类型日常用例是这样子的:
public enum Singleton {
INSTANCE;
//可以省略此方法,通过Singleton.INSTANCE进行操作
public static Singleton getInstance() {
return Singleton.INSTANCE;
}
}