单例模式是一种常用的软件设计模式,其目的是确保一个类仅有一个实例,并提供一个全局访问点来获取这个唯一实例。在Java中,实现单例模式通常需要遵循以下几个关键原则:
-
私有化构造器:将类的构造器声明为
private
,以防止外部代码通过new
操作符直接创建该类的实例。 -
静态工厂方法:提供一个静态方法(通常称为
getInstance()
),用于获取单例对象。这个方法负责检查是否已经创建过实例,如果尚未创建,则创建并保存;如果已存在,则直接返回该实例。 -
确保线程安全:在多线程环境中,必须确保单例对象的创建过程是线程安全的,即无论何时何地,无论多少个线程同时请求,都只会创建一个实例。
以下是几种常见的Java单例模式实现方式及其示例:
1. 饿汉式(静态常量)
优点:类加载时即初始化单例,线程安全,无同步开销。
缺点:如果单例实例很庞大或创建过程耗时,可能会导致类加载时较长的初始化时间,且即使从未使用该单例,也会占用内存。
public class SingletonEager {
private static final SingletonEager INSTANCE = new SingletonEager();
private SingletonEager() {}
public static SingletonEager getInstance() {
return INSTANCE;
}
}
2. 懒汉式(线程不安全)
优点:延迟初始化,只有在首次调用getInstance()
时才创建单例。
缺点:线程不安全,多线程环境下可能创建多个实例。
public class SingletonLazyUnsafe {
private static SingletonLazyUnsafe instance;
private SingletonLazyUnsafe() {}
public static SingletonLazyUnsafe getInstance() {
if (instance == null) {
instance = new SingletonLazyUnsafe();
}
return instance;
}
}
3. 懒汉式(线程安全,同步方法)
优点:解决了线程安全问题。
缺点:每次调用getInstance()
都会进行同步,造成不必要的性能损耗。
public class SingletonLazySynchronizedMethod {
private static SingletonLazySynchronizedMethod instance;
private SingletonLazySynchronizedMethod() {}
public static synchronized SingletonLazySynchronizedMethod getInstance() {
if (instance == null) {
instance = new SingletonLazySynchronizedMethod();
}
return instance;
}
}
4. 双重检查锁定(DCL, Double-Checked Locking)
优点:既实现了延迟初始化,又保证了线程安全,且仅在初始化时加锁,性能较高。
缺点:依赖JVM正确实现内存模型,早期JVM版本可能存在DCL失效问题,但在现代JVM中已得到解决。
public class SingletonDCL {
private volatile static SingletonDCL instance;
private SingletonDCL() {}
public static SingletonDCL getInstance() {
if (instance == null) {
synchronized (SingletonDCL.class) {
if (instance == null) {
instance = new SingletonDCL();
}
}
}
return instance;
}
}
5. 静态内部类
优点:利用类加载机制保证线程安全,延迟初始化,无同步开销。
缺点:相比其他实现方式,代码结构稍显复杂。
public class SingletonStaticInnerClass {
private SingletonStaticInnerClass() {}
private static class SingletonHolder {
private static final SingletonStaticInnerClass INSTANCE = new SingletonStaticInnerClass();
}
public static SingletonStaticInnerClass getInstance() {
return SingletonHolder.INSTANCE;
}
}
分析Spring源码中的单例模式及作用
Spring框架广泛使用了单例模式,尤其是在其核心组件BeanFactory
中管理的bean实例。Spring默认将配置文件中定义的bean配置为单例模式,这意味着对于每个指定为单例的bean,Spring容器在整个应用程序生命周期中仅创建一次该bean的实例,并将其缓存起来,后续对该bean的所有请求都将返回相同的实例。
作用:
- 资源优化:对于重量级、高消耗资源的对象(如数据库连接、线程池等),通过单例模式限制实例数量,避免资源浪费。
- 一致性保证:对于需要保持全局唯一状态或共享状态的bean,单例模式确保所有客户端共享同一份实例,从而维持状态的一致性。
- 简化编程模型:开发者无需关心bean实例的创建、管理和销毁,只需关注业务逻辑,降低了代码耦合度。
由于Spring源码庞大且涉及众多模块,这里无法直接给出全部相关源码。但可以简述Spring如何实现单例模式:
Spring的DefaultListableBeanFactory
类(或其他实现BeanFactory
接口的类)是Spring IoC容器的核心实现,它维护了一个DefaultSingletonBeanRegistry
(或类似实现SingletonBeanRegistry
接口的类)来管理单例bean。当容器创建一个bean时,首先检查是否已经存在该bean的单例实例。如果存在,直接从缓存中返回;否则,按照bean定义创建新实例,并将其放入缓存中。
以下是一段简化版的伪代码,以说明Spring如何通过SingletonBeanRegistry
来实现单例模式:文章来源:https://www.toymoban.com/news/detail-856240.html
public interface BeanFactory {
Object getBean(String beanName);
}
public interface SingletonBeanRegistry {
Object getSingleton(String beanName);
void registerSingleton(String beanName, Object singletonObject);
}
public class DefaultListableBeanFactory implements BeanFactory {
private final SingletonBeanRegistry singletonRegistry;
public Object getBean(String beanName) {
return this.singletonRegistry.getSingleton(beanName);
}
}
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
public Object getSingleton(String beanName) {
return this.singletonObjects.get(beanName);
}
public void registerSingleton(String beanName, Object singletonObject) {
this.singletonObjects.putIfAbsent(beanName, singletonObject);
}
}
实际Spring源码中,DefaultSingletonBeanRegistry
及其相关类还包含了许多额外逻辑,如处理循环依赖、bean的后置处理器、生命周期回调等。以上伪代码仅为了说明Spring如何通过一个注册表(registry)来管理单例bean的创建和缓存,确保整个应用中每个bean名称对应唯一实例。文章来源地址https://www.toymoban.com/news/detail-856240.html
到了这里,关于Java基础:单例模式,Spring源码中有哪些单例模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!