什么是单例设计模式
单例模式,是一种常用的软件设计模式。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。
设计的思路是
-
别人不能new实例,所以要将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
-
在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型。
-
定义一个静态方法返回这个唯一对象。
饿汉式
立即加载就是使用类的时候已经将对象创建完毕,不管以后会不会使用到该实例化对象,先创建了再说。常见的实现办法就是直接new实例化。
public class Singleton {
// 将自身实例化对象设置为一个属性,并用static、final修饰
private static final Singleton instance = new Singleton();
// 构造方法私有化
private Singleton() {}
// 静态方法返回该实例
public static Singleton getInstance() {
return instance;
}
}
懒汉式
延迟加载就是调用get()方法时实例才被创建,先不急着实例化出对象,等要用的时候才给你创建出来。常见的实现方法就是在get方法中进行new实例化。
public class Singleton {
// 将自身实例化对象设置为一个属性,并用static修饰
private static Singleton instance;
// 构造方法私有化
private Singleton() {}
// 静态方法返回该实例
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种懒汉式在多线程环境中并不能保证单例的状态,我们必须使用锁机制保证单例状态。具体我们继续往下看
懒汉式+锁机制 简称粗双重检查锁
双重检查锁是线程安全的一种方式,它保证了延迟初始化。这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
public class Singleton {
// volatile如果不加可能会出现半初始化的对象
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 == null有两层判断,表示的是:- 第一层判断保证的是外部的请求进来不会上锁,如果实例已经创建完毕,会直接返回。
- 第二层判断保证的是为了防止生成多个实例
-
加上volatile是防止指令重排,形成半初始化的对象。
内部类实现单例
这种也是懒汉式的一种实现,而且使用这种懒汉式没有任何的线程问题,在Singleton加载的时候,不会加载SingletonHolder,但是调用getInstance方法的时候,因为主动使用了SingletonHolder这个内部类,就会加载这个内部类,一旦加载这个内部类,静态内部类里面的成员变量才会被初始化,最终实现了懒加载。
public class Singleton {
/** 私有化构造器 */
private Singleton() {
}
/** 对外提供公共的访问方法 */
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
/** 写一个静态内部类,里面实例化外部类 */
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
}
枚举实现单例
package com.ydlclass;
public class Singleton {
private Singleton(){}
public static Singleton getInstant(){
return SingletonHolder.INSTANT.instant;
}
private enum SingletonHolder{
INSTANT;
private final Singleton instant;
SingletonHolder(){
instant = new Singleton();
}
}
public static void main(String[] args) {
System.out.println(Singleton.getInstant() == Singleton.getInstant());
}
}