2026-04-20 11:48:52
单例模式(Singleton)是一种创建型模式,确保一个类只有一个实例,并提供全局访问点。 以下从优缺点、具体实现和总结三个方面详细介绍单例模式:
优缺点优点
受控访问:提供了对唯一实例的受控访问,确保全局唯一性。
节约资源:由于在系统内存中只存在一个对象,因此可以节约系统资源,对于需要频繁创建和销毁的对象,单例模式可提高系统性能。
扩展性强:可以根据实际情况需要,在单例模式的基础上扩展做出双例模式、多例模式。
缺点
职责过重:单例类的职责过重,里面的代码可能会过于复杂,在一定程度上违背了“单一职责原则”。
状态丢失:如果实例化的对象长时间不被利用,会被系统认为是垃圾而被回收,这将导致对象状态的丢失。
单例模式的核心是确保一个类只有一个实例,并提供全局访问点。通常通过私有构造器和getInstance()方法实现。以下是六种常见的实现方式:
饿汉式
特点:线程安全,无法实现实例懒加载策略。
实现:在类加载时就初始化实例。
public class Singleton1 { private final static Singleton1 singleton1 = new Singleton1(); private Singleton1() {} public static Singleton1 getInstance() { return singleton1; }}懒汉式
特点:线程不安全,实现了实例懒加载策略。
实现:在第一次调用getInstance()时初始化实例。
public class Singleton2 { private final static Singleton2 singleton2; private Singleton2() {} public static Singleton2 getInstance() { if (singleton2 == null) singleton2 = new Singleton2(); return singleton2; }}全局锁式
特点:线程安全,且实现了懒加载策略,但是线程同步时效率不高。
实现:通过同步方法确保线程安全。
public class Singleton3 { private final static Singleton3 singleton3; private Singleton3() {} public synchronized static Singleton3 getInstance() { if (singleton3 == null) singleton3 = new Singleton3(); return singleton3; }}静态代码块式
特点:线程安全,类主动加载时才初始化实例,实现了懒加载策略,且线程安全。
实现:通过静态代码块初始化实例。
public class Singleton4 { private final static Singleton4 singleton4; private Singleton4() {} static { singleton4 = new Singleton4(); } public static Singleton4 getInstance() { return singleton4; }}双重校验锁式
特点:线程安全,且实现了懒加载策略,同时保证了线程同步时的效率。但是volatile强制当前线程每次读操作进行时,保证所有其他的线程的写操作已完成。volatile使得JVM内部的编译器舍弃了编译时优化,对于性能有一定的影响。
实现:通过双重检查和同步锁确保线程安全。
public class Singleton5 { private static volatile Singleton5 singleton5; private Singleton5() {} public static Singleton5 getInstance() { if (singleton5 == null) { synchronized (Singleton5.class) { if (singleton5 == null) { singleton5 = new Singleton5(); } } } return singleton5; }}静态内部类式
特点:线程安全,不存在线程同步问题,且单例对象在程序第一次getInstance()时主动加载SingletonHolder和其静态成员INSTANCE,因而实现了懒加载策略。
实现:通过静态内部类初始化实例。
public class Singleton6 { private Singleton6() {} private static class SingletonHolder { private static final Singleton6 INSTANCE = new Singleton6(); } public static Singleton6 getInstance() { return Singleton6.SingletonHolder.INSTANCE; }}枚举方式
特点:线程安全,不存在线程同步问题,且单例对象在枚举类型INSTANCE第一次引用时通过枚举的构造函数初始化,因而实现了懒加载策略。
实现:通过枚举类型初始化实例。
public class Singleton7 { private Singleton7() {} enum SingletonEnum { INSTANCE; private final Singleton7 singleton7; private SingletonEnum() { singleton7 = new Singleton7(); } } public static Singleton7 getInstance() { return SingletonEnum.INSTANCE.singleton7; }}这种方式是Effective Java作者Josh Bloch提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。不过,由于JDK 1.5中才加入enum特性,用这种方式写不免让人感觉生疏。
本文总结了七种Java中实现单例模式的方法,其中使用双重校验锁、静态内部类和枚举类的方式可以解决大部分问题。其中,极为推荐静态内部类和枚举类这两种实现方式。