Java 单例模式怎么写
平时我们用手机APP时,打开一次就能一直用的登录状态,或者家里冰箱里固定位置的冷藏层,都是“只保留一个”的设计。软件开发里也有这种需求,比如控制全局的配置信息、数据库连接池,要是不小心创建了多个实例,轻则浪费内存,重则导致程序出错。这时候就需要一种“单例模式”——保证一个类只能有一个实例,同时提供全局访问的方法。
最基础的写法:饿汉式
就像你买早餐,提前到店就把要吃的包子买好放包里,用的时候直接拿出来。饿汉式就是类加载的时候就创建好实例,不管用不用,先占好位置。

代码里只要在类里创建一个静态的私有实例,再写一个公共的静态方法返回这个实例就行。比如写个配置类,提前把参数加载好,程序启动时就生成实例:private static final Config INSTANCE = new Config();,然后对外提供public static Config getInstance() { return INSTANCE; }。这种写法简单,不会出问题,适合小项目,但如果这个实例占内存大,一直不用就会浪费空间。
懒汉式:需要的时候再创建
懒汉式就像你去买咖啡,走到柜台才点单,需要用的时候再生成实例,避免提前浪费。但要注意,多个人同时点单时,会出现重复做咖啡的情况——程序里就是多个线程同时调用getInstance(),可能生成多个实例。
所以要加个synchronized关键字锁住方法,保证同一时间只有一个线程能创建实例:public static synchronized LazySingleton getInstance() { if (INSTANCE == null) { INSTANCE = new LazySingleton(); } return INSTANCE; }。这样就不会重复创建,但每次调用方法都要检查锁,会稍微影响速度,适合单线程或者并发不高的场景。
双重检查锁定:兼顾效率和安全
想解决懒汉式的效率问题,就用双重检查锁定。就像你去便利店买水,先看门口有没有人排队(第一次检查),没人的话再进店,进店后再确认有没有空位(第二次检查),确认后才买。
代码里先判断实例是否存在,不存在才加锁,锁里再检查一次,避免多个线程同时通过第一次检查:if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } }。这里还要加volatile关键字,防止指令重排序导致实例没初始化就被使用,适合并发高的场景。
枚举式:最简洁的安全写法
除了上面几种,还有一种更简单的枚举写法。就像你家里的电源插座,不管有多少电器插,插座本身只有一个,用枚举就能天然保证单例。
直接写public enum Singleton { INSTANCE; },用的时候直接Singleton.INSTANCE调用就行,不仅写法简单,还能防止反射和反序列化破坏单例,是现在推荐的写法。
单例模式的核心是“唯一实例”,选哪种写法要看项目场景:小项目用饿汉式,并发不高用懒汉式,高并发用双重检查锁定,追求简洁安全就用枚举式。不管哪种写法,只要保证类只有一个实例,就能满足大部分需要全局唯一对象的开发场景。