软件帮帮网
柔彩主题三 · 更轻盈的阅读体验

单例模式怎么实现?几种常见写法一看就懂

发布时间:2025-12-12 05:53:01 阅读:10 次

做开发时,有些对象其实只需要一个就够了,比如数据库连接池、配置管理器、日志实例。这时候用单例模式就很合适——保证整个程序运行期间,某个类只存在一个实例。

饿汉式:提前把实例创建好

这种方式在类加载的时候就把实例new出来了,简单直接,线程安全,但可能浪费资源,因为还没用到就已经创建了。

public class Singleton {
    private static final Singleton instance = new Singleton();
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        return instance;
    }
}

懒汉式:用的时候再创建

只有调用getInstance()时才创建实例,节省内存。但多线程环境下可能出问题,多个线程同时判断instance为空,就会生成多个实例。

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

加锁的懒汉式:线程安全版

加上synchronized关键字,确保同一时间只有一个线程能进入创建逻辑。虽然安全了,但每次调用都得加锁,性能有点拖后腿。

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

双重检查锁定:又安全又高效

只在第一次创建时加锁,后续直接返回实例。既保证线程安全,又避免重复加锁,是实际项目中常用的写法。注意要把instance声明为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;
    }
}

静态内部类:懒加载 + 线程安全

利用类加载机制保证线程安全。SingletonHolder在外部类加载时不会被初始化,只有调用getInstance()时才会触发,从而实现懒加载。写法简洁,推荐使用。

public class Singleton {
    
    private Singleton() {}
    
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

比如你写个App,想让音乐播放器全局只有一个,避免多个声音冲突,用单例就特别合适。选哪种实现方式,得看你的场景:追求简单就用饿汉,讲究性能就上双重检查或静态内部类。