当前位置: 首页 > news >正文

总结单例模式的写法(在线程安全的情况下)

目录

1 饿汉模式

2 懒汉模式 

3 分析


啥是设计模式? 设计模式好⽐象棋中的 "棋谱". 红⽅当头炮, ⿊⽅⻢来跳. 针对红⽅的⼀些⾛法, ⿊⽅应招的时候有⼀ 些固定的套路. 按照套路来⾛局势就不会吃亏. 软件开发中也有很多常⻅的 "问题场景". 针对这些问题场景, ⼤佬们总结出了⼀些固定的套路. 按照这 个套路来实现代码, 也不会吃亏.

单例模式能保证某个类在程序中只存在唯⼀⼀份实例, ⽽不会创建出多个实例.

这⼀点在很多场景上都需要. ⽐如 JDBC 中的 DataSource 实例就只需要⼀个.

单例模式具体的实现⽅式有很多. 最常⻅的是 "饿汉" 和 "懒汉" 两种

1 饿汉模式

饿汉模式(迫切) 程序启动, 类加载之后,立即创建出实例.

//单例模式 (饿汉模式)

class Singleton {

    private static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }
    // 做出一个限制, 禁止别人去 new 这个实例!!
    private Singleton() {}

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

 

2 懒汉模式 

懒汉模式(延时) 则是在第一次使用实例的时候, 再创建. 否则能不创建就不创建.

// 单例模式(懒汉模式)
class SingletonLazy {
    private static SingletonLazy instance = null;

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

    private SingletonLazy() {}
}

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

3 分析

那么上述两种模式, 谁是线程安全的. 换句话说, 在多线程调用getInstance的情况下, 哪个代码是线程安全的(不会有bug).

先分析饿汉模式.

再来看懒汉模式.

 

那么如何解决上述问题呢?

首先想到的就是加锁, 我们要让判断和赋值操作绑在一起.

 

但是加锁是一个成本较高的操作, 可能会引起阻塞等待. 

加锁的基本原则, 应该是非必要, 不加锁. 不能无脑加锁. 如果无脑加锁, 就会导致程序执行效率受到影响.

Vector, HashTable, StringBuffer ....都是在关键方法上写了synchronized .
无论是单线程使用,还是多线程使用, 无论是否场景存在线程安全问题, 都是会加锁的, 也都会影响到效率, 都不太建议使用.

但是代码还是有一些问题.

 

 

 

经过上述的优化中后, 线程安全的懒汉模式代码就成了这个样子.

// 单例模式(懒汉模式)
class SingletonLazy {
    private static volatile SingletonLazy instance = null;
    //instance是null, 就说明是首次调用, 就需要加锁. 如果是非null, 就说明是后续调用,就不需要加锁
    public static SingletonLazy getInstance() {
        if (instance == null) {
            synchronized (SingletonLazy.class) {
                if (instance == null) {
                    instance = new SingletonLazy();
                }
            }
        }
        return instance;
    }

    private SingletonLazy() {}
}

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

相关文章:

  • 深入解析 MySQL 8 C++ 源码:二级索引回表操作
  • Redis7——基础篇(二)
  • QT异步编程之QMetaObject::invokeMethod
  • Windows桌面系统管理8:项目实施
  • 青少年编程都有哪些比赛可以参加
  • 网络安全大数据架构 网络安全之数据安全
  • RMSNorm算子的CUDA实现
  • MacOS Docker 安装指南
  • GO语言基础知识
  • ES,怎么实现查询一万条数据
  • mysql索引为什么用B+树不用,B树或者红黑树
  • 303. 区域和检索 - 数组不可变
  • Lab12_ Blind SQL injection with conditional errors
  • 测试WSS服务器
  • N-bit ADC过采样和L阶噪声整形后的SQNR表达式
  • 自动化测试面试会问哪些?
  • Python中的数学问题3-math、pow
  • 【大模型】-名词手册-扫盲
  • 分类预测 | MFO-LSSVM飞蛾扑火算法优化最小二乘支持向量机多特征分类预测Matlab实现
  • swupdate升级文件系统内文件与分区的差异
  • 宜昌全域高质量发展:机制创新与产业重构的双向突围
  • 国家主席习近平会见斯洛伐克总理菲佐
  • 构建菌株有效降解有机污染物,上海交大科研成果登上《自然》
  • 北外滩集团21.6亿元摘上海虹口地块,为《酱园弄》取景地
  • 国家出口管制工作协调机制办公室部署开展打击战略矿产走私出口专项行动
  • 异域拾异|大脚怪的形状:一项神秘社会学研究