1.单例模式有哪几种常见的实现方式?

目录

1.问题

2.知识储备

(1).SpringBoot的Bean注册和DI(依赖注入)

[1].SpringBoot的Bean注册

{1}.基于@Component及其衍生注解

{2}.基于@Bean注解

[2].SpringBoot的DI

{1}.什么是DI

{2}.常见的DI注解

(2).单例模式

[1].什么是单例模式

[2].单例模式的常见实现方式

{1}.饿汉式(立即加载)

{2}.懒汉式(延迟加载,线程不安全)

{3}.懒汉式(线程安全,synchronized修饰方法)

[{4}.双重检查锁定(DCL,Double-Checked Locking)](#{4}.双重检查锁定(DCL,Double-Checked Locking))

3.分析

4.解决方案:

(1).基于饿汉式实现单例模式:

(2).基于线程不安全懒汉式实现单例模式:

(3).基于线程安全懒汉式实现单例模式:

(4).基于DCL实现单例模式

5.小结


1.问题

小编有在写工具项目,是一个纯javase项目,没有使用springboot等框架 。因此遇到了一个问题,我发现有的类我需要重复的使用,但是在不同的类或者方法中,导致每次都需要进行创建,这样性能是比较差的 。以往在springboot中小编都是直接通过@Component注册,然后通过@Autowired注入的。在这里由于是Javase原生项目无法使用这种方式。小编思考了一下,可以使用单例模式来解决我这个需求。

2.知识储备

想要理解和解决这个问题,一些知识储备是必不可少的。

(1).SpringBoot的Bean注册和DI(依赖注入)

需要注意的是SpringBoot的Bean注册和DI,当然是需要依赖SpringBoot环境的。

[1].SpringBoot的Bean注册

众所周知,SpringBoot的一个很显著的特点,就是可以把类交给SpringBoot来管理,而不需要手动管理。那么Bean注入就是这个特点的前提,只有通过Bean注入明确把哪些类交给SpringBoot管理,SpringBoot才能帮我们管理

Bean注册的常见方式:

{1}.基于@Component及其衍生注解

这是最常用的方式了,通过注解标识类,让Spring自动扫描并注册Bean

@Component

衍生注解:@Controller(控制层)、@Service(服务层)、@Repository(数据层)

以下是一段使用了衍生注解的示例代码:

java 复制代码
// 业务层Bean(@Service是@Component的衍生注解)
@Service
public class UserService {
    // 业务逻辑...
}

// 控制层Bean
@Controller
public class UserController {
    // 业务逻辑...
}
{2}.基于@Bean注解

通过在配置类中使用@Bean注解,手动定义Bean的创建逻辑,适合注册第三方类(如工具类、框架组件)或者需要自定义实例化过程的Bean

使用方式:在被@Configuration标识的配置类中,定义返回值为目标类型的方法,并添加@Bean注解

以下是一段使用了@Bean注解的示例代码:

java 复制代码
// 配置类(标识为配置类)
@Configuration
public class AppConfig {

    // 注册一个RestTemplate实例到容器
    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        // 自定义配置(如添加拦截器、设置超时时间等)
        restTemplate.getInterceptors().add(new LoggingInterceptor());
        return restTemplate;
    }

    // 注册一个自定义工具类Bean
    @Bean(name = "dateUtils") // 可通过name指定Bean名称(默认是方法名)
    public DateUtils createDateUtils() {
        return new DateUtils();
    }
}

[2].SpringBoot的DI

{1}.什么是DI

DI(Dependecy Injection)依赖注入,是Spring框架中实现控制反转(IOC)的核心思想。其核心思想是:让 Spring 容器负责将一个对象(依赖)自动 "注入" 到另一个依赖它的对象中,而不是由对象自己创建或查找依赖。

SpringBoot三大特性:AOP、IOC、DI

{2}.常见的DI注解

@Autowired:Spring最常用的DI注解,先根据类寻找,然后再根据名寻找

以下是一段基于@Autowired完成DI的代码:

java 复制代码
@Service
public class UserService {
    // 字段注入
    @Autowired
    @Qualifier("userRepositoryImpl") // 配合@Qualifier指定Bean名称(解决同类型冲突)
    private UserRepository userRepo;

    // 构造器注入(单构造器时可省略@Autowired)
    @Autowired
    public UserService(UserRepository userRepo) {
        this.userRepo = userRepo;
    }

    // Setter方法注入
    @Autowired
    public void setUserRepo(UserRepository userRepo) {
        this.userRepo = userRepo;
    }
}

@Resource:先根据名找,在根据类寻找

以下是一段**基于@**Resource完成DI的代码:

java 复制代码
@Service
public class OrderService {
    // 按字段名"paymentService"匹配Bean(若不存在则按类型)
    @Resource
    private PaymentService paymentService;

    // 通过name属性指定Bean名称(优先按名称匹配)
    @Resource(name = "alipayService")
    public void setPaymentService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}

(2).单例模式

[1].什么是单例模式

单例模式是一种常用的设计模式,其核心是保证一个类在整个应用中只有一个实例,并提供一个全局访问点。

[2].单例模式的常见实现方式

常见的实现方式有以下几种,各有特点和使用场景

{1}.饿汉式(立即加载)

原理:在类加载时就创建实例,确保线程安全,但是可能提前占用资源

特点:简单直观,天然线程安全(因为类加载过程是线程安全的),但是无论是否使用都会创建实例,可能造成资源浪费。

以下是饿汉式的一段示例代码:

java 复制代码
public class A{
    private static final A INSTANCE= new A();
    private A(){}
    public static A getInstance(){
        return INSTANCE;
    }
}
{2}.懒汉式(延迟加载,线程不安全)

原理:在首次调用getInstance时才创建实例,实现延迟加载,但多线程环境下可能创建多个实例

特点:节省资源,线程不安全,不适合多线程场景

以下是懒汉式的一段示例代码:

java 复制代码
public class B{
    private static B INSTANCE;
    private B(){}
    public static  B getInstance(){
        if(INSTANCE==null){
            INSTANCE = new B();
        }
        return INSTANCE;
    }
}
{3}.懒汉式(线程安全,synchronized修饰方法)

原理:在getInstace()方法上添加synchroninzed关键字,强制多线程排队访问,保证线程安全。

特点:为了解决懒汉式的线程安全问题,但是每次调用方法都要加锁,性能开销比较大。

以下**是懒汉式(线程安全)**的一段示例代码:

java 复制代码
public class C{
    private static C instance ;
    private C(){}
    public static synchronized C getInstance(){
        if(instace==null){
            instance = new C();
        }
        return instance 
    }
}
{4}.双重检查锁定(DCL,Double-Checked Locking)

原理:结合懒加载和锁机制,仅在实例未创建时加锁,同时通过volatile关键字防止指令重排,兼顾性能和线程安全

特点:懒加载、线程安全、性能好,是实际开发中常用的方式

以下是DCL的一段示例代码:

java 复制代码
public class D{
    private static volatile D instace;
    private D(){}
    public static D getInstace(){
         // 第一次检查:未创建时才进入同步块(提高性能)
        if(instance==null){
            synchronized(D.class){
                  // 第二次检查:防止多线程同时进入同步块后重复创建
                if(instance==null){
                    instace = new D();
                }
            }
        }
        return instance;
    }
}

3.分析

之所以需要手写单例模式,主要还是因为是基于javase,如果是基于springboot其实大多数情况是不需要我们手写的。大家一定不要重复造轮子。写这个文章是为了让大家能在无法借助springboot时来实现单例的!

4.解决方案:

(1).基于饿汉式实现单例模式:

java 复制代码
public class A{
    private static final A INSTANCE= new A();
    private A(){}
    public static A getInstance(){
        return INSTANCE;
    }
}

(2).基于线程不安全懒汉式实现单例模式:

java 复制代码
public class B{
    private static B INSTANCE;
    private B(){}
    public static  B getInstance(){
        if(INSTANCE==null){
            INSTANCE = new B();
        }
        return INSTANCE;
    }
}

(3).基于线程安全懒汉式实现单例模式:

java 复制代码
public class C{
    private static C instance ;
    private C(){}
    public static synchronized C getInstance(){
        if(instace==null){
            instance = new C();
        }
        return instance 
    }
}

(4).基于DCL实现单例模式

java 复制代码
public class D{
    private static volatile D instace;
    private D(){}
    public static D getInstace(){
         // 第一次检查:未创建时才进入同步块(提高性能)
        if(instance==null){
            synchronized(D.class){
                  // 第二次检查:防止多线程同时进入同步块后重复创建
                if(instance==null){
                    instace = new D();
                }
            }
        }
        return instance;
    }
}

5.小结

什么你都看到小结了?你难道就是传说中的"勤奋者"?

在本文,

1.你学会了SpringBoot的Bean注册和BI

2.你学会了什么是单例模式,以及四种实现单例模式的方式

注:如果发现文章有错别字、理解错误、语义错误等问题,请联系作者修改。大家一起努力才能创建更好的生态!

相关推荐
编程岁月4 小时前
java面试-0136-BIO、NIO、AIO区别?
java·面试·nio
春生野草4 小时前
部署项目到Tomcat
java·tomcat
安逸sgr4 小时前
SpringMVC启动流程
java·jvm·spring·spring cloud·eclipse·tomcat·maven
MOON404☾4 小时前
Rust程序语言设计(5-8)
开发语言·后端·rust
lifallen5 小时前
从Apache Doris 学习 HyperLogLog
java·大数据·数据仓库·算法·apache
fire-flyer5 小时前
maven-jlink-plugin入门
java·maven
Knight_AL5 小时前
Java 单元测试全攻略:JUnit 生命周期、覆盖率提升、自动化框架与 Mock 技术
java·junit·单元测试
bkspiderx5 小时前
C++设计模式之行为型模式:迭代器模式(Iterator)
c++·设计模式·迭代器模式
cominglately5 小时前
记录一次生产环境数据库死锁的处理过程
java·死锁