定义
一个类只有一个实例,且该类能自行创建这个实例的一种模式。
特点
- 只有一个实例对象。
- 该实例对象必须由单例类自行创建。
- 单例类对外提供一个访问该类的方法。
UML图
单例模式的实现
主要有两种:饿汉式单例、懒汉式单例
饿汉式单例
类一旦加载就创建为一个实例对象,保证在调用getInstance()方法前该实例对象就已经存在
懒汉式单例
类加载时不创建唯一实例,在调用getInstance()方法时创建唯一实例对象并返回
(1).线程不安全。
public class SingletonOne {
private static SingletonOne singleton = new SingletonOne();
private SingletonOne() {
super();
}
public static SingletonOne getInstance() {
return singleton;
}
}
(2).线程安全,使用synchronized对getInstance()方法加锁。
public class SingletonTwo {
private static SingletonTwo singleton;
private SingletonTwo() {
super();
}
public static SingletonTwo getInstance() {
if (singleton == null) {
singleton = new SingletonTwo();
}
return singleton;
}
}
(3).线程安全,双检锁/双重校验锁(DCL,即 double-checked locking)
使用volatile对修饰唯一实例singleton,保证singleton的可见性,使用synchronized修饰初始化singleton的代码块。
public class SingletonFour {
private static volatile SingletonFour singleton;
private SingletonFour() {
super();
}
public static SingletonFour getInstance() {
if (singleton == null) {
synchronized (SingletonFour.class) {
if (singleton == null) {
singleton = new SingletonFour();
}
}
}
return singleton;
}
}
(4).线程安全,登记式/静态内部类
使用静态内部类SingletonHolder,调用getInstance()方法实例化SingletonHolder,初始化一个唯一实例
虚拟机会保证一个类的类构造器()在多线程环境中被正确的加锁、同步,
如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的类构造器(),其他线程都需要阻塞等待,直到活动线程执行()方法完毕。
特别需要注意的是,在这种情形下,其他线程虽然会被阻塞,但如果执行()方法的那条线程退出后,其他线程在唤醒之后不会再次进入/执行()方法。
因为在同一个类加载器下,一个类型只会被初始化一次。如果在一个类的()方法中有耗时很长的操作,就可能造成多个线程阻塞,在实际应用中这种阻塞往往是隐藏的。
public class SingletonFive {
private static class SingletonHolder {
private static final SingletonFive INSTANCE = new SingletonFive();
}
private SingletonFive() {
super();
}
public static final SingletonFive getInstance() {
return SingletonHolder.INSTANCE;
}
}
(5).线程安全,使用枚举
public enum SingletonSix {
INSTANCE;
}