1. 懒汉式:
public class Singleton {
//1. 本类内部创建对象实例
private static Singleton instance = null;
//2. 构造方法私有化,不允许外部new
private Singleton(){}
//3. 提供一个公有的静态方法,返回实例对象
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
懒汉式单例模式在调用时先判断实例是否存在,如果存在就直接使用,如果不存在就创建一个实例。(以时间换空间)
不加同步的懒汉式是线程不安全的,因为可能同时两个线程都判断到对象不存在,然后都new一个对象。
因此,需要使用双重检查加锁的方法。
一个线程想要访问对象,必须先获取到对象的监视器(monitor),synchronized最大的特征就是在同一时刻只有一个线程能够获得对象的监视器。
用volatile修饰对象实例用来限制指令重排序。Java类初始化过程是非原子操作,会经历三个阶段:
(1)分配内存给这个对象
(2)初始化对象
(3)将引用指向刚分配的内存空间
其中(2)和(3)可能会指令重排序,也就是说执行顺序可能是123也可能是132。所以如果执行顺序是132,那么当线程执行完3,此时对象已经不为空,但是并没有初始化。此时另一个线程抢占了CPU,那么执行getInstance()方法时就会直接返回instance(非 null 但却没有初始化),后续使用就会出错了。
public class Singleton {
//1. 本类内部创建对象实例,加volatile禁止指令重排序
private static volatile Singleton instance = null;
//2. 构造方法私有化,不允许外部new
private Singleton(){}
//3. 提供一个公有的静态同步方法,返回实例对象
public static synchronized Singleton getInstance() {
//4.第一次判空检查,主要是为了效率,当instance为null的时候,才进入synchronized代码段
if (instance == null) {
//5. new之前加锁
synchronized (Singleton.class) {
//6. 第二次判空检查,主要是为了防止可能出现多个实例
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
2. 饿汉式:
public class Singleton {
//1. 创建实例
private static Singleton instance = new Singleton();
//2. 构造方法私有化,不允许外部new
private Singleton() {}
//3. 提供一个公有的静态同步方法,返回实例对象
public static Singleton getInstance() {
return singleton;
}
}
饿汉式在类加载的时候就会创建实例,在调用时不需要再判断了。(以空间换时间)
3. 使用静态内部类实现单例模式:
public class Singleton {
//1. 静态内部类,只会在虚拟机装载类的时候初始化一次
private static class SingletonHolder {
private static Singleton instance = new Singleton();
}
//2. 构造方法私有化,不允许外部new
private Singleton(){}
//3. 提供一个公有的静态同步方法,返回实例对象
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
当getInstance方法第一次被调用的时候,它会返回SingletonHolder.instance,导致SingletonHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建Singleton的实例,由于是静态的域,因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。
参考&鸣谢:
-《java 单例模式的几种实现方式》
https://blog.csdn.net/fd2025/article/details/79711198
-《单例模式中的懒汉式以及线程安全性问题》
https://www.cnblogs.com/sunnyDream/p/8011186.html