如何在Java中实现线程安全的单例模式?

在Java中,单例模式(Singleton Pattern)是一种常用的设计模式,用于确保一个类只有一个实例,并提供全局访问点。为了让单例在多线程环境下保持线程安全,常用的实现方式有以下几种:

  1. 双重检查锁(Double-Check Locking)
    通过在 getInstance() 方法中先检查实例是否为 null,再加同步锁,内部再次检查,最终只在第一次创建时进入同步块。需要注意 volatile 关键字保证可见性和防止指令重排。

    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;
        }
    }
  2. 静态内部类(Initialization-on-demand holder idiom)
    利用类加载机制,确保实例化只在第一次调用 getInstance() 时发生,并天然线程安全。该方式最简洁、性能最佳。

    public class Singleton {
        private Singleton() {}
    
        private static class Holder {
            private static final Singleton INSTANCE = new Singleton();
        }
    
        public static Singleton getInstance() {
            return Holder.INSTANCE;
        }
    }
  3. 枚举实现
    Java 枚举类型天然具备序列化安全性和线程安全。只需定义一个枚举常量即可。

    public enum Singleton {
        INSTANCE;
    
        public void doSomething() {
            // 业务逻辑
        }
    }

    使用时:Singleton.INSTANCE.doSomething();

  4. 使用 synchronized 方法
    直接把 getInstance() 方法加 synchronized,简单但每次调用都会产生同步开销,适用于不频繁访问的场景。

    public class Singleton {
        private static Singleton instance;
    
        private Singleton() {}
    
        public static synchronized Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }

选择建议

  • 对性能要求极高且只需要单例一次时,推荐使用 静态内部类枚举
  • 如果你想兼顾懒加载与多线程安全,双重检查锁 是经典实现。
  • 若代码简洁为首要目标且对并发量不敏感,可以直接使用 synchronized 方法。

通过上述实现方式,Java 中的单例模式可以在多线程环境下保持线程安全,同时避免了多实例化导致的资源浪费。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注