- 使用 synchronized 修饰 getInstance 方法
确保了只有一个线程可以同时访问 getInstance 方法。这意味着在任何时候只有一个线程可以执行 getInstance() 方法,从而避免了多个线程同时创建多个实例的情况,因此是线程安全的。
java
public class ClientUtil {
private static ClientUtil clientUtil;
private ClientUtil() {}
public static synchronized ClientUtil getInstance() {
if (null == clientUtil) {
clientUtil = new ClientUtil();
clientMap = new HashMap<String, ApiClient>();
}
return clientUtil;
}
}
但是,这种实现方式会在每次调用 getInstance() 方法时都获取锁,这可能会影响性能,尤其是在高并发的情况下。因为只有一个线程可以访问该方法,其他线程必须等待当前线程释放锁才能继续执行。
- 使用双重检查锁定(Double-Checked Locking)机制 优化性能
核心思想是在首次检查对象是否为 null 时进行同步,以确保只有一个线程可以创建对象,而后续的检查则不需要同步,以提高性能。
java
public class ThreadSafeSingleton {
// 私有静态变量,存储单例实例
private static volatile ThreadSafeSingleton instance;
// 私有构造函数,防止外部实例化
private ThreadSafeSingleton() {}
// 公有静态方法,获取单例实例
public static ThreadSafeSingleton getInstance() {
// 双重检查锁定,确保只有一个线程创建实例
if (instance == null) {
synchronized (ThreadSafeSingleton.class) {
// 再次检查实例是否已经被创建
if (instance == null) {
instance = new ThreadSafeSingleton();
}
}
}
return instance;
}
// 其他业务方法
public void doSomething() {
System.out.println("Singleton instance is doing something.");
}
}
instance 变量使用了 volatile 关键字,确保多线程环境下对它的读取和写入操作都是原子的,并且对所有线程可见。
构造函数 ThreadSafeSingleton() 被声明为私有,确保外部无法直接实例化 ThreadSafeSingleton。
getInstance() 方法使用了双重检查锁定机制,在多线程环境下保证了只有一个线程创建实例。首先检查 instance 是否为 null,如果为 null,则进入同步块,再次检查 instance 是否为 null,如果仍然为 null,则创建一个新的 ThreadSafeSingleton 实例。