javaEE——单例模式

目录

前言

本篇文章来介绍单例模式,并讲述在保证线程安全的前提下,单例模式的写法。

1.概念

单例模式是一种设计模式,可以说是写代码的一种模板,如果在一些固定的场景下按照设计模式进行写代码,写出来的代码一定不会很差。

设计模式有非常多种,这里就介绍单例模式这一种。

单例指的是单个实例,在一些场景中,我们希望一个类只能有唯一的实例,我们就可以使用单例模式这种设计模式。

2. 实现

下面介绍如何在Java中实现单例模式,单例模式有很多种实现方法,在这里我们就介绍两种最常用的:饿汉式和懒汉式。

饿汉式是先创建一个静态的实例,通过getInstance方法来获取这个唯一的实例,下面看例子:

java 复制代码
//单例模式之饿汉式
class Singleton{
    //先创建一个静态的实例
    private static Singleton instance = new Singleton();

    public static Singleton getInstance(){
        return instance;
    }
    
    private Singleton(){
        //私有化构造方法
    }
}

public class Demo23 {
    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        System.out.println(s1 == s2); // true
    }
}

注意,要将构造方法私有化,来防止外部自行创建新的实例。

懒汉式则是在第一次调取getInstance方法时,才会创建实例,下面看示例:

java 复制代码
//单例模式之懒汉式
class SingletonLazy {
    private static SingletonLazy instance;

    private SingletonLazy() {
        //私有化构造方法
    }

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

public class Demo24 {
    public static void main(String[] args) {
        SingletonLazy s1 = SingletonLazy.getInstance();
        SingletonLazy s2 = SingletonLazy.getInstance();
        System.out.println(s1 == s2); // true
    }
}

3. 比较和改进

如果我们在多线程条件下调用getInstance,不难发现,懒汉模式线程不安全,因为在多个线程调用getInstance时,可能会判定到好几次instance == null,这样会导致创建好几个不同的实例。在饿汉模式下,由于已经提前创建好实例,调用getInstance只会返回这个实例,所以线程安全。

下面对懒汉模式进行改进,保证其线程安全:

java 复制代码
//单例模式之懒汉式
class SingletonLazy {
    private static volatile Object locker = new Object();
    private static SingletonLazy instance;

    private SingletonLazy() {
        //私有化构造方法
    }

    public static SingletonLazy getInstance() {
        if (instance == null) {
            synchronized (locker){
                if (instance == null) {
                    instance = new SingletonLazy();
                }
            }
        }


        return instance;
    }
}

对实例化对象进行加锁,由于每次一个线程都要先加锁,操作过于繁琐,所以在外层再添加一个判断条件,判断instance是否被实例化,如果实例化则直接返回instance,不需要再进行加锁判断,在此之后,还要给locker加上volatile关键字,防止编译器优化,这里的编译器优化是"指令重排序",而进行优化之后,多线程进行操作的时候会出现问题,导致instance还没有初始化就被返回,这是指令重排序而造成的线程安全问题。

总结

这篇文章简单介绍了线程安全模式下单例模式的写法,希望对大家有所帮助。

相关推荐
Bazingga1 小时前
Java16 record 完整拆解——语法、语义、限制、反射
java·后端
SL_staff3 小时前
规则联动:给工厂装上‘自动化神经反射弧’——JVS·物联网平台规则引擎实战教程
java·人工智能·物联网
骑着蜗牛撵大象3273 小时前
Linux 进程间通信之管道:从 pipe() 的内核语义到 FIFO 落地排错
android·java·linux·系统编程·fifo·管道·进程间通信
WJ.Polar3 小时前
Java封装、继承、多态
java·开发语言
ly76893 小时前
PostgreSQL 备份恢复策略:pg_basebackup、WAL 归档与 PITR 在企业 Java 系统中的落地
java·数据库·postgresql·pitr·pg_basebackup·wal 归档
摇滚侠3 小时前
Java 中如何表示负数,有符号和无符号的区别,补码的计算规则,char byte short int long 的范围
java·开发语言
奇牙coding4 小时前
Codex CLI 升级后多文件编辑静默失效:config.yaml 枚举变更排查与修复指南
java·前端·javascript·ai
小羊没烦恼!4 小时前
Ajax与JSON的一些总结
android·java·前端·数据库·mysql·算法·okhttp
Lhappy嘻嘻4 小时前
读懂 JVM:内存模型、类加载机制、分代回收
java·开发语言·jvm
黄俊懿4 小时前
【架构师从入门到进阶】第六章:服务集群优化——第八节:线程数公式
java·服务器·数据库·分布式·性能优化·架构·系统架构