在Java中,单例模式是一种常见的设计模式,用于确保一个类只有一个实例,并提供一个全局访问点。以下是一些常见的创建Java单例模式的方法:
1. 饿汉式(线程安全)
在类加载时就完成了实例化,避免了线程同步问题。
public class Singleton { | |
private static Singleton instance = new Singleton(); | |
// 私有构造方法,防止被实例化 | |
private Singleton() {} | |
// 静态工厂方法 | |
public static Singleton getInstance() { | |
return instance; | |
} | |
} |
2. 懒汉式(线程不安全)
在第一次调用getInstance()
方法时才进行实例化。但这种简单的实现在多线程环境下是不安全的。
public class Singleton { | |
private static Singleton instance; | |
// 私有构造方法,防止被实例化 | |
private Singleton() {} | |
// 静态工厂方法 | |
public static Singleton getInstance() { | |
if (instance == null) { | |
instance = new Singleton(); | |
} | |
return instance; | |
} | |
} |
3. 懒汉式(线程安全,同步方法)
使用synchronized
关键字来保证线程安全。但这种方式性能较低,因为每次调用getInstance()
时都会进行同步。
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 volatile static Singleton instance; | |
// 私有构造方法,防止被实例化 | |
private Singleton() {} | |
// 静态工厂方法 | |
public static Singleton getInstance() { | |
if (instance == null) { | |
synchronized (Singleton.class) { | |
if (instance == null) { | |
instance = new Singleton(); | |
} | |
} | |
} | |
return instance; | |
} | |
} |
注意:在Java 5及以后的版本中,volatile
关键字是必需的,以确保instance
变量的可见性和禁止指令重排序。
5. 静态内部类(线程安全)
利用JVM的类加载机制来保证初始化instance
时只有一个线程。这种方式既能确保线程安全,又能避免同步带来的性能开销。
public class Singleton { | |
private Singleton() {} | |
// 静态内部类 | |
private static class SingletonHolder { | |
private static final Singleton INSTANCE = new Singleton(); | |
} | |
// 静态工厂方法 | |
public static Singleton getInstance() { | |
return SingletonHolder.INSTANCE; | |
} | |
} |
6. 枚举(线程安全)
使用枚举类型来创建单例是Java 5之后推荐的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。
public enum Singleton { | |
INSTANCE; | |
// 其他方法... | |
} |
在枚举类型中,每个枚举常量在JVM中都是唯一的。因此,枚举类型天然就是单例的。这种方式不仅简洁,而且由JVM从根本上提供支持,绝对防止多次实例化,是更简洁、高效、安全的实现单例的最佳方式。