单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
单例模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
单例模式特点1、只能有一个实例。
2、必须自己创建自己的唯一实例。
3、必须给所有其他对象提供这一实例。
单例模式分类 1、饿汉式1、私有化构造方法
2、在类中创建一个本类对象
3、提供一个全局静态方法获取到该对象
描述: 线程安全,比较常用,但容易产生垃圾,因为一开始就初始化
优点: 没有加锁,执行效率较高
缺点: 类加载时就初始化,浪费内存
例子:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
2、懒汉式
①懒汉式:线程不安全
此方式是最基本的实现,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式,在多线程不能正常工作
例子:
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
②懒汉式:线程安全但是效率不高
描述: 这种方式具备很好的延迟加载,能够在多线程中工作,但是效率很低,大多数情况下不需要同步
优点: 第一次调用才初始化,避免内存浪费
缺点: 必须加 synchronized 锁才能保证单例,但加锁会影响效率
例子:
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
③懒汉式:线程安全且高性能
线程安全,延迟初始化,此方式采用双锁机制DCL(double-checked locking),安全且在多线程情况下能保持高性能
例子:
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实例变量有效,解决该问题
另外2种实现单例模式的方法
①静态内部类实现单例
这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用
这种方式利用了 classloader 机制来保证初始化 instance 时只有一个线程,它和饿汉式不同的是:饿汉式只要 Singleton 类被装载了,那么 instance 就会被实例化(没有达到 lazy loading 效果),而这种方式是 Singleton 类被装载了,instance 不一定被初始化。只有通过显式调用 getInstance 方法时,才会显式装载 Singleton 类,从而实例化 instance
例子:
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
②枚举实现单例
这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化
例子:
public enum Singleton {
INSTANCE;
public Singleton getInstance() {
return INSTANCE;
}
}
完整的枚举实现单例
public class Person {
//私有化构造函数
private Person(){ }
//定义一个静态枚举类
static enum SingletonEnum{
//创建一个枚举对象,该对象天生为单例
INSTANCE;
private Person person;
//私有化枚举的构造函数
private SingletonEnum(){
person = new Person();
}
public Person getInstnce(){
return person;
}
}
//对外暴露一个获取User对象的静态方法
public static Person getInstance(){
return SingletonEnum.INSTANCE.getInstnce();
}
}



