- 饿汉式
// 饿汉式单例模式
public class Singleton {
// 利用类加载机制在类初始化时创建实例对象
private static Singleton instance = new Singleton();
// 构造函数私有化,防止可以直接new出对象
private Singleton() {
}
// 直接返回类初始化时的对象
public static Singleton getInstance() {
return instance;
}
}
- 懒汉式
// 懒汉式单例模式
public class Singleton {
// 类初始化时未创建实例
private static Singleton instance;
// 构造函数私有化,防止可以直接new出对象
private Singleton() {
}
// 等到需要时才创建对象(延迟加载
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
如果getInstance()方法未被同步,并且线程A和线程B同时调用此方法,则执行if (instance == null)语句时都为真,那么线程A和线程B都会创建一个对象,在内存中就会出现两个对象,这样就违反了单例模式。多线程模式下可以使用synchronized关键字修饰getInstance方法,但是会影响性能。
- 双重检测
// 双重检测单例模式
public class Singleton {
// 类初始化时未创建实例
private static volatile Singleton instance;
// 构造函数私有化,防止可以直接new出对象
private Singleton() {
}
// 等到需要时才创建对象
public static Singleton getInstance() {
if (instance == null) { // 第一次检测不为null时直接返回
synchronized (Singleton.class) {
if (instance == null) { // 第二次检测线程安全
instance = new Singleton();
}
}
}
return instance;
}
}
- 内部类
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
private static Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
- 枚举
public enum Singleton {
INSTANCE;
public static Singleton getInstance() {
return INSTANCE;
}
}
枚举本身就是单例的
单例验证
public class Client {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2);
}
}
如果打印的结果为true的话,说明两个对象是同一个对象,就是符合单例模式的。
使用场景
如果系统中某个类只需要单个实例,那么可以使用单例模式,并且提供全局唯一的访问点。比如系统一般会提供单例的Configuration实例用于访问配置项。