饿汉式单例(Eager Singleton)是线程安全的。这种实现方式在类加载时就创建了单例实例,因此在多线程环境中,不存在多个线程同时创建实例的问题。
以下是一个饿汉式单例的示例:
public class EagerSingleton {
// 在类加载时立即创建实例
private static final EagerSingleton instance = new EagerSingleton();
// 私有构造函数
private EagerSingleton() {
// Initialization code
}
// 提供全局访问点
public static EagerSingleton getInstance() {
return instance;
}
}
提前实例化:通过在类加载时创建实例,确保了在任何线程访问 getInstance()
方法之前,实例已经被创建。
无同步开销:由于实例在类加载时就已创建,后续的访问不需要任何同步操作,提高了性能。
饿汉式单例适合以下场景:
饿汉式单例的缺点在于:
总之,饿汉式单例是线程安全的,适合特定场景,但在设计时需要根据需求仔细选择实现方式。
懒汉式单例(Lazy Singleton)在默认实现中并不是线程安全的。多个线程同时访问 getInstance()
方法时,可能会导致多个实例的创建。为了确保线程安全,需要采取适当的同步措施。
以下是一个不安全的懒汉式单例示例:
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
// Initialization code
}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton(); // 可能会导致多个线程创建多个实例
}
return instance;
}
}
getInstance()
方法时,可能会同时发现 instance
为 null
,从而各自创建新的实例,导致多个实例存在。synchronized
关键字:public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
// Initialization code
}
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
这种方式确保了在同一时刻只有一个线程可以执行 getInstance()
方法,避免了多个实例的创建。
public class LazySingleton {
private static volatile LazySingleton instance;
private LazySingleton() {
// Initialization code
}
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}
volatile 关键字的作用:
3.通过静态内部类实现,利用 Java 的类加载机制确保线程安全。
public class Singleton {
private Singleton() {
// Initialization code
}
private static class SingletonHelper {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHelper.INSTANCE;
}
}
使用静态内部类来实现单例模式是一种优雅且高效的方法。以下是这种实现方式的一些主要优点:
默认的懒汉式单例实现是线程不安全的。要确保线程安全,可以使用同步机制或其他设计模式。推荐静态内部类来实现
以下是使用静态内部类实现的单例模式的示例,包括一个 main
函数,展示如何调用并验证单例的行为。
public class Singleton {
private Singleton() {
// Initialization code
}
private static class SingletonHelper {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHelper.INSTANCE;
}
}
public class Main {
public static void main(String[] args) {
// 创建多个线程来测试单例
Runnable task = () -> {
Singleton instance = Singleton.getInstance();
System.out.println("Instance HashCode: " + instance.hashCode());
};
// 启动多个线程
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
Thread thread3 = new Thread(task);
thread1.start();
thread2.start();
thread3.start();
// 等待线程执行完成
try {
thread1.join();
thread2.join();
thread3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 主线程再次获取实例
Singleton mainInstance = Singleton.getInstance();
System.out.println("Main Thread Instance HashCode: " + mainInstance.hashCode());
}
}
单例类:Singleton
类使用静态内部类实现了单例模式,确保了线程安全和延迟初始化。
主函数:
Runnable
任务,任务中调用 Singleton.getInstance()
并打印实例的哈希码。getInstance()
并打印该实例的哈希码。你应该会看到所有线程打印的哈希码相同,表明它们获取的是同一个实例。例如:
Instance HashCode: 123456789
Instance HashCode: 123456789
Instance HashCode: 123456789
Main Thread Instance HashCode: 123456789
这个示例展示了如何使用静态内部类实现单例模式,并通过多线程验证了其线程安全性。所有线程和主线程都获取到了同一个实例,验证了单例模式的有效性。