简单的单例实现
public class Singleton {
public static int STATUS=1;
private Singleton() {
System.out.println("Singleton is create");
}
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
这是一个典型的饿汉式的单例模式。
优点:
- 线程安全:在类加载阶段就完成了实例化,避免了多线程同步。
- 获取速度快:实例已经加载完成,可以直接返回
- 防止反射攻击
缺点:
- 内存浪费:无论是否使用,它都会创建
- 启动延迟:如果单例的初始化很耗时,会延迟应用的启动时间
懒加载的单例
public class LazySingleton {
private LazySingleton() {
System.out.println("LazySingleton is create");
}
private static LazySingleton instance = null;
public static synchronized LazySingleton getInstance() {
if (instance == null)
instance = new LazySingleton();
return instance;
}
}
懒加载的思想是:最初并不需要实例化instance,⽽是当getInstance()⽅法被第⼀次调⽤时,创建单例对象。但这会引出线程同步的问题,因此需要使用synchronized来锁住同步。
双重检查的懒汉式
public class Singleton {
// 关键:使用 volatile 修饰
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton(); // 现在安全了
}
}
}
return instance;
}
}
有人评价它十分的丑陋和复杂,因此不做过多叙述。
静态内部类单例
public class Singleton {
private Singleton() {}
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE; // 这里才会触发类加载,实现懒加载
}
}
静态内部类是一个独立的类,它与外部类没有绑定关系。静态内部类和其外部类在编译后会生成两个独立的字节码文件(.class文件)这意味着:
- 不会随外部类加载而加载:加载
Singleton类时,不会自动加载Holder类 - 有自己的类加载时机:
Holder类只在被引用时才加载
因此上述的单例模式,只有在调用Holder.INSTANCE时才会创建实例,其线程安全有JVM进行保证:
当多个线程同时首次调用getInstance()时:
- 第一个线程触发
Holder类的加载 JVM的类加载机制保证<clinit>(类初始化方法)只会被执行一次- 其他线程会等待类加载完成
- 所有线程都得到同一个已初始化的实例