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

Java【多线程】单例模式

目录

单例模式

饿汉模式

懒汉模式

懒汉模式-多线程版


单例模式

单例模式是一种设计模式

设计模式相当于棋谱

棋谱,大佬把一些对局整个推演过程,写出来

设计模式,是属于程序员的棋谱

单例模式(单个实例/对象),就是设计模式中一种非常典型的模式,也是比较简当的模式,还是校招中最容易被考到的设计模式

强制要求某个类某个程序中只有唯一一个实例

(不允许创建多个实例,不允许new多次)

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

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


饿汉模式

类加载的同时, 创建实例.

class Singleton{
    private static Singleton instance = new Singleton();
    private Singleton(){};
    public static Singleton getInstance(){
        return instance;
    }
}

静态成员的初始化,是在类加载的阶段触发的

类加载往往就是在程序一启动就会触发

后续统一通过getInstance这个方法类获取这里的实例

构造方法使用private

单例模式的点睛之笔

在类外面进行new操作都会编译失败


懒汉模式
类加载的时候不创建实例. 第⼀次使⽤的时候才创建实例.
其实上述懒汉/饿汉模式存在缺陷
这两个版本的getInstance在多线程环境下调用会出bug
上述懒汉模式这个写法getInstance是线程不安全的
线程安全问题发⽣在⾸次创建实例时. 如果在多个线程中同时调⽤ getInstance ⽅法, 就可能导致创建 出多个实例

加上 synchronized 可以改善这⾥的线程安全问题
当把实例创建好之后
后续再调用getInstance此时都是直接执行return
如果只是进行if+return,纯粹的读操作
读操作,不涉及线程安全问题
但是每次调用上述的方法都会触发一次加锁操作

多线程情况下这里的加锁就会互相阻塞影响程序的执行效率


加锁 / 解锁是⼀件开销⽐较⾼的事情. ⽽懒汉模式的线程不安全只是发⽣在⾸次创建实例的时候. 因
此后续使⽤的时候, 不必再进⾏加锁了.
外层的 if 就是判定下看当前是否已经把 instance实例创建出来了

使⽤双重 if 判定, 降低锁竞争的频率

public static SingletonLazy getInstance(){
        if(instance==null){//判定是否需要加锁
            synchronized (SingletonLazy.class){
                if(instance==null){//判断是否需要new对象
                    instance = new SingletonLazy();
                }
            }
        }
        return instance;
    }

按需加锁,如果实例已经创建过了就不涉及线程安全问题


再仔细分析,可能存在“内存可见性问题”
为了稳妥起见,可以给Instance直接加上一个volatile
private static volatile SingletonLazy instance = null;

更关键的问题是指令重排序

编译器会在逻辑不变的前提下调整代码执行的先后顺序,以达到提升性能的效果

volatile的功能有两方面

1.确保每次读取操作,都是读内存

2.关于该变量的读取和修改操作,不会触发重排序


懒汉模式-多线程版
class SingletonLazy {
    private static volatile SingletonLazy instance = null;
    public static SingletonLazy getInstance(){
        if(instance==null){
            synchronized (SingletonLazy.class){
                if(instance==null){
                    instance = new SingletonLazy();
                }
            }
        }
        return instance;
    }
    private SingletonLazy(){

    }
}
当多线程⾸次调⽤ getInstance, ⼤家可能都发现 instance 为 null, 于是⼜继续往下执⾏来竞争锁,
其 中竞争成功的线程, 再完成创建实例的操作.
当这个实例创建完了之后, 其他竞争到锁的线程就被⾥层 if 挡住了. 也就不会继续创建其他实例

http://www.kler.cn/news/364743.html

相关文章:

  • 【css-在一个元素中设置font-size和实际渲染字体大小不一致】
  • Geranium天竺葵:位置修改、守护进程管理器、清理器、屏幕时间删除器和 TrollStore 监督器
  • java动态代理介绍
  • Pytorch常用函数汇总【持续更新】
  • 要做消息列表的颜色切换
  • 装了Ubuntu和Windows双系统,如何设置默认启动Windows
  • 网络安全资源导航
  • pycharm 中提示ModuleNotFoundError: No module named ‘distutils‘
  • 啊!?异常重启竟然是KV惹的祸!快来看看怎么回事?
  • 红队攻防 | 凭证获取的10个方法,零基础入门到精通,收藏这一篇就够了
  • locust断点调试(pdb)
  • Linux 字符设备驱动 之 无法归类的《杂项设备驱动》
  • @SpringBootApplication
  • CSS揭秘:7. 伪随机背景
  • Sigrity Power SI Model Extraction模式如何提取电源网络的S参数和阻抗操作指导(一)
  • java脚手架系列10-统一缓存、分布式锁
  • 怎么做系统性能优化
  • WPF:Binding数据绑定
  • 接地电阻柜的生产流程
  • java项目之电影评论网站(springboot)
  • 【linux】centos7 安装openjdk-17
  • 笔记:WPF中MarkupExtension使用的IServiceProvider参数都有哪些
  • 星海智算:【王宝宝-ComfyUI-SD3】无需部署一键启动
  • ARM学习(33)英飞凌(infineon)PSOC 6 板子学习
  • 回归、分类模型的评估指标
  • G1(Garbage First)垃圾回收实战