【多线程案例】单例模式

2023-09-14 21:53:55

单例模式是设计模式的一种,先谈谈什么是设计模式?

大家应该都知道棋谱、剑谱之类的,就是一些“高手”在经历过长期的累计之后,更具经验写出的具有固定套路的处理“方法”,只要按照这个套路来,在对局之中必然是不会吃亏的,甚至能够一招制敌。

那么在我们日常的开发中也有大佬们针对一些十分常见的场景,抽象出固定的套路。一些小白在学习了大佬总结的设计模式之后,就像是掌握了套路,针对适用的场景就不会吃亏。

单例模式的使用场景是什么呢?单例模式能够保证某个类的在程序中只存在唯一的一份,就算是new多个实例,实际上也是同一份。

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

单例模式的具体实现方式可以分为 饿汉模式 和 懒汉模式:

饿汉模式:

类加载的同时创建实例。

class Singleton{
    //static 修饰 是类属性 直接在类加载的时候将实例创建出来,饿汉模式
    private static Singleton instance = new Singleton();


    //为了避免Singleton类不小心被复制出多份
    //将构造方法设置为private。这样在类外面就没有办法通过new的方式来创建 Singleton这个实例了
    private Singleton() {

    }

    public static Singleton getInstance(){
        return instance;
    }
}

懒汉模式-单线程版本

类加载的时候不创建实例. 第一次使用的时候才创建实例.

class SingletonLazy{
    private static SingletonLazy instance = null;

    private SingletonLazy(){

    }

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

懒汉模式-多线程版本

为什么这里的懒汉模式需要考虑多线程版本呢?因为上面的单线程的代码存在线程安全的问题。不安全是因为在getInstance当中有对instance的写操作,涉及到写操作的时候就要小心了。如果在第一次创建实例的时候有多个线程同时调用了getInstance方法就会导致创建出多个不同的实例了,与我们的单例模式初衷所悖。因此需要对这里的写操作加锁:

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

懒汉模式-多线程改进版本

上面的代码还存在着两个不足

  1. 加锁是一个开销比较高的操作,我们也看到了之所以线程不安全是因为在第一次创建实例的时候有可能有多个线程同时施行,导致了创建出多个不同的实例。那么我们只需要针对首次创建实例的时候加锁,后续的操作就没有必要加锁了。这样可以提升很大的效率。
  2. 同时为了避免“内存可见性”导致读取的instance存在偏差,于是补充上volatile
class SingletonThread {
    private static volatile SingletonThread instance = null;

    private SingletonThread() {

    }

    public static SingletonThread getInstance() {
        if (instance == null) {
            synchronized (SingletonThread.class) {
                if (instance == null) {
                    instance = new SingletonThread();
                }
            }
        }

        return instance;
    }
}

注意理解两个if判定。

虽然两个if的判定条件是一样的但是两者的含义却大大不同。第一个if判定是判定instance是否是第一次创建,如果没有创建的话就开始创建实例并且加锁。第二个if判定抢夺到锁后,instance是否已经被创建了。两个if语句不可以省略任意一个。

更多推荐

一篇关于vue的入门的详细介绍

目录一.介绍二.库和框架的区别三.什么是MVVM模式四.实例4.1.Vue开发示例4.2.双向数据绑定4.3.生命周期好啦,今天的分享就到这了,希望能够帮到你呢!😊😊一.介绍Vue.js是一种流行的JavaScript框架,用于构建用户界面。它被设计为一个渐进式框架,可以逐步应用到现有项目中,也可以作为一个完整的单

【JVM】Java类的加载机制!

一、类的生命周期类加载过程包含:加载、验证、准备、解析和初始化,一共包括5个阶段。(1)加载:简单来说就是将java类的字节码文件加载到机器内存中。在加载类时,Java虚拟机必须完成以下3件事情:通过类的完全限定名称获取定义该类的二进制字节流。将该字节流表示的静态存储结构转换为Metaspace元空间区的运行时存储结构

科锐逆向第二阶段(一)SDK

基本概念什么是SDKSDK是软件开发工具包(SoftwareDevelopmentKit)的缩写。它是一个集成了软件开发所需工具、库文件、示例代码和文档等资源的软件包。SDK通常由软件开发公司或平台提供,旨在帮助开发人员构建、测试和部署特定类型的应用程序、库或服务。它提供了一套开发工具,使开发人员能够利用平台或框架的功

idea把项目打成jar包步骤详解

最近产品需要预研一个小功能,开始后在本地开发测试好之后,需要打成jar提供出去,今天弄完了,决定把这个步骤记录下来,便于以后轻车熟路。打成jar要有mian方法的入口,所以我们在代码中需要定义一个main方法,然后通过这个main方法调用我们的核心逻辑代码。下面是我的代码示例:publicstaticvoidmain(

基于微信小程序的图书管理系统设计与实现(源码+lw+部署文档+讲解等)

前言💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗👇🏻精彩专栏推荐订阅👇🏻2023-2024年最值得选的微信小程序毕业设计选题大全:100个热门选

使用 OpenWRT 设置 Banana Pi BPI-R3开源硬件路由器

这里介绍如何使用pfSense将ZimaBoard216设置为防火墙的链接。我们正在为小型板计算机建立一个专用网络,这样当我开始教授Linux时,我就可以显示和共享它的IP。现在为我的网络设置一条到pfSense后面的路由。这是为了提供另一个级别的安全性。我有两台Banana-Pi路由器1)Banana-PiR2Pro

【案例教学】华为云API图引擎服务 GES的便捷性—AI帮助快速处理图片小助手

云服务、API、SDK,调试,查看,我都行阅读短文您可以学习到:人工智能AI快速处理图片1IntelliJIDEA之API插件介绍API插件支持VSCodeIDE、IntelliJIDEA等平台、以及华为云自研CodeArtsIDE,基于华为云服务提供的能力,帮助开发者更高效、便捷的搭建应用。API插件关联华为云服务下

虹科教您 | 可实现带宽计量和延迟计算的时间敏感网络测试工具RELY-TSN-LAB操作指南与基本功能测试

1.RELY-TSN-LAB产品概述时间敏感网络(TSN)能够合并OT和IT世界,这将是真正确保互操作性和标准化的创新性技术。这项技术的有效开发将显著降低设备成本、维护、先进分析服务的无缝集成以及减少对单个供应商的依赖。为了在这些网络中实现确定性,需要控制连接到网络的设备的延迟和带宽,并预测其在拥堵和错误情况下的行为。

利用Windows搭建Emby媒体库服务器,轻松实现无公网IP的远程访问

文章目录1.前言2.Emby网站搭建2.1.Emby下载和安装2.2Emby网页测试3.本地网页发布3.1注册并安装cpolar内网穿透3.2Cpolar云端设置3.3Cpolar内网穿透本地设置4.公网访问测试5.结语1.前言在现代五花八门的网络应用场景中,观看视频绝对是主力应用场景之一,加上移动网络技术的发展,随时

【RNN从入门到实战】GRU入门到实战——使用GRU预测股票。

摘要GRU是LSTM网络的一种效果很好的变体,它较LSTM网络的结构更加简单,而且效果也很好,因此也是当前非常流形的一种网络。GRU既然是LSTM的变体,因此也是可以解决RNN网络中的长依赖问题。在LSTM中引入了三个门函数:输入门、遗忘门和输出门来控制输入值、记忆值和输出值。而在GRU模型中只有两个门:分别是更新门和

跳槽面试:如何转换工作场所而不失去优势

🌷🍁博主猫头虎带您GotoNewWorld.✨🍁🦄博客首页——猫头虎的博客🎐🐳《面试题大全专栏》文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺🌊《IDEA开发秘籍专栏》学会IDEA常用操作,工作效率翻倍~💐🌊《100天精通Golang(基础入门篇)》学会Golang语言,畅玩云原生,走遍大

热文推荐