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

多线程案例-单例模式

“风不来见我 我自去见风”

 

前面说到了一些关于多线程的话题,那么下面的这几篇文章围绕着多线程来说一些案例,那么第一篇便是多线程案例之单例模式。

什么是单例模式:

单例模式是一种设计模式,确保在整个应用程序中只有一个类的实例,并且提供一个全局访问点。

单例模式的作用:

  1. 控制实例数目:确保类只有一个实例,防止创建多个对象,节省资源。
  2. 全局访问:提供一个全局访问点,可以通过该点访问唯一的实例。
  3. 延迟初始化:单例对象可以在第一次使用时创建,有助于提高性能。
  4. 节约资源:对于需要频繁访问的对象或服务,使用单例模式可以减少内存消耗。

单例常见用例:

  • 数据库连接池:通常我们只需一个连接池来管理多个数据库连接。
  • 日志管理:只有一个日志管理实例,统一处理日志信息。
  • 配置管理:配置类可以在整个应用中共享,同步配置状态。

饿汉版单例:

public class ThreadHungerSingle {

    private static ThreadHungerSingle instance = new ThreadHungerSingle();

    public static ThreadHungerSingle getInstance() {
        return instance;
    }

    //单例模式最关键部分
    private ThreadHungerSingle() {};
}

 饿汉 的意思就是 “迫切”,在类的加载的时候,就会被创建出这个单例的实例。

懒汉版单例:

public class ThreadLazySingle {

    private static ThreadLazySingle instance = null;

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

    private ThreadLazySingle() {};
}

懒汉 的特点就是 “懒”,在计算机中,“懒”是一个褒义词呢。只有在被用到时,才会真正创建出实例。

那么对于上述的两个版本,如果是在多线程环境下,调用getInstance时,谁会存在线程安全问题呢?

显然地是我们的懒汉版单例在多线程环境下会存在问题,饿汉版只是单纯的“读”操作,而懒汉版会有“写”操作,下面我们一起来看看这个图便知道了:

存在线程安全问题的话,此时我们就需要进行 加锁 操作来解决了,那么代码如下:

class ThreadLazySingle2 {
    private static ThreadLazySingle2 instance = null;
    private static final Object locker = new Object();
    public static ThreadLazySingle2 getInstance() {
        synchronized (locker) {
            if(null == instance) {
                instance = new ThreadLazySingle2();
            }
        }
        return instance;
    }

    private ThreadLazySingle2() {};
}

加了锁之后确实解决了线程安全问题,但是加锁同样也可能带来阻塞。如果上述代码,已经new完对象了,那么后续的代码都是单纯的“读”操作,此时调用getInstance也是线程安全的,那么就没有必要加锁了。所以我们可以在前面加上同样的判断:

class ThreadLazySingle2 {

    private static ThreadLazySingle2 instance = null;
    private static final Object locker = new Object();

    public static ThreadLazySingle2 getInstance() {

        if(null == instance) {
            synchronized (locker) {
                if(null == instance) {
                    instance = new ThreadLazySingle2();
                }
            }
        }
        return instance;
    }

    private ThreadLazySingle2() {};
}

上述两个相同的判断条件看起来好像是有问题的,但是它们各有各的用处,第一个条件判断,判断的是是否需要进行加锁,第二个条件判断,判断的是是否需要进行实例对象。对于锁之间的阻塞,我们无法预测它们会阻塞多久,可能会是“沧海桑田”。

指令重排序:

上述代码中,还存在一个问题,可能会因为编译器的优化带来指令重排序的线程安全问题。什么是指令重排序呢:是计算机体系结构中的一种优化技术,主要指处理器或编译器在不改变程序最终结果的前提下,重新排列指令的执行顺序,以提高性能(如减少流水线停顿、提高缓存命中率等)。

instance = new ThreadLazySingle2();这里我分为三步进行举例说明:1.分配地址空间 2.执行构造方法 3.内存空间的地址,赋值给引用变量。我们一起来看一看,在多线程环境下,他会存在什么样的问题呢:

怎样解决指令重排序的问题呢,也是使用我们的关键字 volatile ,加上 volatile 关键字之后,编译器就会发现 instance 是 “易失” 的,便不会进行上述的优化,所以我们的最终版本是这样的:

class ThreadLazySingle1 {
    private static volatile ThreadLazySingle1 instance = null;
    private static final Object locker = new Object();

    public static ThreadLazySingle1 getInstance() {
        //此处的if判定是否需要加锁
        if(null == instance) {
            //由于只需要第一次创建出来实例就行,后续的代码,都是单纯的 读 操作,此时 getInstance不加锁也是 线程安全的,没有必要加锁
            //当前写法,只要调用getInstance,都会触发加锁操作,此时虽然没有加锁操作了,但是也会因为加锁,产生阻塞,影响到性能
            synchronized (locker) {
                //此处的if判断是否要创建对象
                if(null == instance) {
                    //这个代码可能会因为指令重排序,引起线程安全问题 所以上面应该加上 volatile 关键字
                    instance = new ThreadLazySingle1();
                }
            }
        }
        return instance;
    }

    private ThreadLazySingle1() {};
}

因此 Java 的volatile 有两个功能:1.保证内存可见性 2.禁止指令重排序

好了,我们本期的内容就讲到这里了,我们下期再见!!! 

相关文章:

  • Tcp套接字编程
  • go - grpc入门
  • 5G_WiFi_CE_杂散测试
  • C语言入门教程100讲(0)从了解C语言的发展史开始
  • 3月29日星期六今日早报简报微语报早读
  • 【Qt】Qt 类的继承与内存管理详解:QObject、信号槽与隐式共享
  • Conda配置Python环境
  • 实时目标检测新突破:AnytimeYOLO——随时中断的YOLO优化框架解析
  • 侯捷 C++ 课程学习笔记:C++ 中引用与指针的深度剖析
  • CS2 DEMO导入blender(慢慢更新咯)
  • Mayo Clinic Platform在人工智能医疗领域的现状及启示意义研究
  • 深度学习——图像余弦相似度
  • 基于华为设备技术的端口类型详解
  • 嵌入式八股RTOS与Linux--中断篇
  • vue如何实现前端控制动态路由
  • 基于pycatia的CATIA零部件激活状态管理技术解析
  • Centos7,tar包方式部署rabbitmq-3.7.6
  • C++ 初阶总复习 (16~30)
  • 液压式精密矫平机——以稳定压力,成就工业级平整
  • CVPR-2025 | 南洋理工基于图表示的具身导航统一框架!UniGoal:通用零样本目标导航方法
  • 俄罗斯延长非法滞留外国人限期离境时间至9月
  • 五一假期上海铁路预计发送446万人次,同比增长8.4%
  • 黄仁勋访华期间表示希望继续与中国合作,贸促会回应
  • 大家聊中国式现代化|陶希东:打造高水平安全韧性城市,给群众看得见的安全感
  • 中国航天员乘组完成在轨交接,神十九乘组将于29日返回地球
  • 起底网红热敷贴“苗古金贴”:“传承人”系AI生成,“千年秘方”实为贴牌货