在Java 5之前,创建Singleton模式需要手动处理多线程环境下的同步问题,以确保实例的唯一性。以下是几种常见的实现方法:
1. 饿汉式(Eager Initialization)
饿汉式在类加载时就创建单例实例,线程安全,但无法懒加载。
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
// 私有构造函数
}
public static Singleton getInstance() {
return INSTANCE;
}
}
2. 懒汉式(Lazy Initialization)
懒汉式在第一次调用时创建实例,但在多线程环境下不安全。
public class Singleton {
private static Singleton instance;
private Singleton() {
// 私有构造函数
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3. 线程安全的懒汉式(Thread-Safe Lazy Initialization)
使用sychronized关键字保证线程安全,但性能较差。
public class Singleton {
private static Singleton instance;
private Singleton() {
// 私有构造函数
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
4. 双重检查锁定(Double-Checked Locking)
结合了懒汉式和饿汉式的优点,保证了线程安全和性能。
public class Singleton {
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;
}
}
5. 静态内部类(Static Inner Class)
利用类加载机制,保证线程安全且支持懒加载。
public class Singleton {
private Singleton() {
// 私有构造函数
}
private static class SingletonHelper {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHelper.INSTANCE;
}
}
说明
- 饿汉式:简单但不支持懒加载。
- 懒汉式:懒加载但线程不安全。
- 线程安全的懒汉式:保证线程安全但性能较差。
- 双重检查锁定:线程安全且性能较好,但实现复杂。
- 静态内部类:线程安全、性能好且实现简单。
以下是带有测试代码的完整示例,展示了如何在Java 5之前使用双重检查锁定(Double-Checked Locking)实现Singleton模式,并在main方法中进行测试:
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 void someMethod() {
System.out.println("Hello from Singleton!");
}
// main方法,测试Singleton
public static void main(String[] args) {
// 获取Singleton实例并调用方法
Singleton singleton1 = Singleton.getInstance();
singleton1.someMethod();
// 验证多次调用getInstance()是否返回同一个实例
Singleton singleton2 = Singleton.getInstance();
System.out.println("Are both instances the same? " + (singleton1 == singleton2));
}
}
解释
-
volatile关键字:
- 确保
instance变量的可见性和有序性,防止指令重排序。
- 确保
-
双重检查锁定:
- 第一次检查:避免不必要的同步。
- 第二次检查:确保线程安全地创建实例。
-
someMethod方法:
- 示例方法,模拟单例类中的业务逻辑。
-
main方法:
- 测试代码,通过
getInstance()方法获取单例实例,并调用someMethod()方法。 - 验证多次调用
getInstance()方法是否返回同一个实例。
- 测试代码,通过
运行结果
Hello from Singleton!
Are both instances the same? true
使用Enum实现Singleton模式在Java中非常简单和高效。下面是一个完整的示例,展示如何使用枚举来实现Singleton:
public enum Singleton {
INSTANCE;
// 可以定义其他方法和变量
public void someMethod() {
System.out.println("Hello from Singleton!");
}
}
// 使用示例
public class SingletonTest {
public static void main(String[] args) {
Singleton singleton = Singleton.INSTANCE;
singleton.someMethod();
}
}
说明
-
定义Singleton枚举:
Singleton枚举定义了一个单一的实例INSTANCE。- 可以在枚举中添加方法和变量,与普通类一样。
-
使用Singleton:
- 在客户端代码中,通过
Singleton.INSTANCE来获取唯一实例。 - 可以调用实例的方法,如
someMethod()。
- 在客户端代码中,通过
优点
- 线程安全:枚举类型的线程安全性由JVM保证,无需额外的同步机制。
- 防止反序列化:枚举类型防止反序列化创建新的实例。
- 防止反射攻击:反射无法破解枚举的单例模式。