单例、多例的区别及如何实现

单例多例是软件设计中对象实例管理的两种模式,主要区别在于对象的实例数量和管理方式。

1. 概念

单例模式 (Singleton)

单例模式确保一个类在整个应用运行期间只有一个实例,并提供一个全局访问点来访问该实例。

  • 特点:
    • 全局唯一。
    • 节省资源,尤其是需要频繁创建和销毁对象的场景(如数据库连接池)。
    • 提供统一的访问接口。
多例模式 (Prototype/Multiton)

多例模式允许一个类在运行时存在多个实例,每个实例可能有不同的状态,通常通过工厂模式或其他方式管理。

  • 特点:
    • 每次需要时都可以创建新的实例。
    • 每个实例独立,不会相互影响。
    • 适合短生命周期对象,或者需要多个不同配置对象的场景。

2. 单例和多例的区别

特点单例模式多例模式
实例数量全局唯一,整个应用程序共享一个实例。可以有多个实例,每次获取可以不同。
内存消耗只创建一次,节省内存和资源。每次创建新实例,内存消耗可能较多。
适用场景配置管理类、线程池、日志管理、数据库连接池等。游戏角色、图形对象、Web 请求处理等。
并发问题需要考虑多线程环境下的实例同步问题。一般无需担心,但管理实例的数量可能需要关注。
实现复杂度实现较复杂,尤其是线程安全的单例实现。实现简单,实例管理交由外部处理即可。

3. 单例的实现

单例模式的实现有多种方式,根据是否需要线程安全和延迟加载,可以选择不同方案。

(1) 饿汉式单例
  • 特点: 类加载时就创建实例,线程安全,但可能造成资源浪费。
public class Singleton {
    private static final Singleton INSTANCE = new Singleton();

    private Singleton() { }

    public static Singleton getInstance() {
        return INSTANCE;
    }
}
(2) 懒汉式单例
  • 特点: 在第一次调用时创建实例,节省资源,但需要考虑线程安全。

线程不安全版本:

public class Singleton {
    private static Singleton instance;

    private Singleton() { }

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

线程安全版本 (双重检查锁):

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;
    }
}
(3) 静态内部类
  • 特点: 延迟加载,线程安全,推荐使用。
public class Singleton {
    private Singleton() { }

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

4. 多例的实现

多例模式通常通过工厂模式容器管理实现。以下是常见的实现方式。

(1) 工厂模式

根据需要创建不同实例。

public class Multiton {
    private static final Map<String, Multiton> instances = new HashMap<>();
    private final String value;

    private Multiton(String value) {
        this.value = value;
    }

    public static Multiton getInstance(String key) {
        return instances.computeIfAbsent(key, k -> new Multiton(k));
    }

    public String getValue() {
        return value;
    }
}
(2) Spring 的原型模式 (Prototype Scope)

在 Spring 框架中,通过配置 @Scope 注解实现多例。

@Component
@Scope("prototype")
public class PrototypeBean {
    public PrototypeBean() {
        System.out.println("PrototypeBean 实例化");
    }
}

每次从容器获取时都会创建一个新实例:

ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
PrototypeBean bean1 = context.getBean(PrototypeBean.class);
PrototypeBean bean2 = context.getBean(PrototypeBean.class);

System.out.println(bean1 == bean2); // 输出 false

5. 应用场景总结

单例适合场景
  1. 全局唯一对象:配置管理器、线程池、日志记录器、数据库连接池。
  2. 高性能场景:频繁访问的对象需要复用,避免多次创建和销毁。
多例适合场景
  1. 每次需要不同实例:Web 请求处理器、图形对象、游戏中多角色管理。
  2. 状态独立的对象:每个实例有不同的配置或数据。

总结

  • 单例强调的是全局唯一性,适合资源共享或需要集中管理的场景。
  • 多例注重实例的独立性和多样性,适合需要频繁创建对象或分开管理状态的场景。
  • 选择哪种模式要根据具体的业务需求和资源管理策略来决定。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值