-
饿汉式(Eager Initialization):在类加载时就创建实例,线程安全,但可能会造成资源浪费。
public class Singleton {private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;} }
-
懒汉式(Lazy Initialization):在第一次调用获取实例方法时才创建实例,可能存在线程安全问题。
public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;} }
- 双重检查锁(Double-Checked Locking):在懒汉式基础上加入双重检查锁,解决线程安全问题,避免每次获取实例都加锁静态内部类(Static Inner Class)
/*** 双重检测锁实现单例模式(使用volatile):解决指令重排可能带来的问题* volatile只保证可见性、有序性、禁止指令重排序、不保证原子性* 1.可见性(Visibility):* 当一个变量被声明为 volatile 后,线程在读取这个变量的值时,会直接从主内存中读取,而不是从线程的工作内存中读取。* 任何对该变量的修改都会立即被其他线程所看到,从而确保了变量的可见性。** 2.禁止指令重排序(Prevents Reordering):* volatile 关键字还可以防止编译器对代码的优化,以避免指令重排序。这样可以确保代码的执行顺序符合程序员的预期。** 3.不保证原子性(Not Atomic):* volatile 关键字能够保证变量的可见性和禁止指令重排序,但并不能保证操作的原子性。对于涉及多步操作的情况,* volatile 不能替代 synchronized。** 4.适用场景:* volatile 适用于状态标志、双重检查锁定(Double-Checked Locking)、单例模式等场景,其中需要保证变量的可见性,但不需要原子性。** 5.内存语义:* 当一个变量被声明为 volatile 后,对这个变量的读写操作将具有内存语义,即对该变量的操作不会被重排序,保证了多线程环境下的线程安全性。**/ public class Singleton {private Singleton() {}private static volatile Singleton instance = null;public static Singleton getInstance(){if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;} }
- 静态内部类(Static Inner Class):利用静态内部类的特性实现延迟加载和线程安全。
public class Singleton {private Singleton() {}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();} }
-
枚举(Enum):利用枚举的特性实现单例,天然线程安全,防止反射和序列化问题。
public enum Singleton {INSTANCE;// 可以添加其他方法或属性 }
6.防止反射打破单例:在单例类的构造函数中添加逻辑,以防止反射攻击并确保单例只被 创建一次:
private Singleton() {if (instance != null) {throw new RuntimeException("Singleton instance already exists. Use getInstance() method to get the instance.");}
}