Java中实现单例模式的常见方式有两种:懒汉式和饿汉式。以下是这两种方式的简单示例:
饿汉式
饿汉式单例模式在类加载时就完成了实例的初始化,以空间换时间,确保了实例的唯一性。
java
public class Singleton {
// 在自己内部定义自己一个实例,是不会被外界访问的
private static final Singleton instance = new Singleton();
// 构造器私有化,外部无法直接通过new来实例化对象
private Singleton() {}
// 对外提供一个公共的静态方法,返回唯一实例
public static Singleton getInstance() {
return instance;
}
}
懒汉式
懒汉式单例模式只有在真正需要使用时,才会创建实例,实现了懒加载。
java
public class Singleton {
// 声明变量
private static Singleton instance = null;
// 构造器私有化
private Singleton() {}
// 提供一个静态方法,当使用到该方法时,才去创建instance
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
懒汉式虽然实现了懒加载,但是在多线程环境下可能会创建多个实例,因此需要加锁处理,这就是上面示例中使用synchronized
关键字的原因。但是,加锁会影响效率。
java
public class Singleton {
public static void main(String[] args) {
Runnable task = () -> {
Singleton1 instance = Singleton1.getInstance();
System.out.println(instance);
};
for (int i = 0; i < 100; i++) {
new Thread(task).start();
}
}
}
class Singleton1 {
private static Singleton1 instance;
private Singleton1() {
System.out.println("LazySingleton instance created.");
}
public static Singleton1 getInstance() {
if (instance == null) {
instance = new Singleton1();
}
return instance;
}
}
双重检查锁定(Double-Checked Locking)
为了解决懒汉式的线程安全问题,同时又不牺牲效率,可以使用双重检查锁定模式。
java
public class Singleton {
// 使用volatile关键字保其可见性和有序性
private static volatile Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
这种方式既实现了线程安全,又避免了每次调用getInstance
方法时都需要进行同步。
枚举方式
Java语言规范提供的一种更简洁的单例实现方式是使用枚举。
java
public enum Singleton {
INSTANCE;
public void someMethod() {
// 实例方法
}
}
使用枚举方式实现单例不仅简洁,而且提供了序列化机制,并由JVM从根本上提供保障,避免多次实例化,是实现单例模式的最佳方法。