【JavaEE】单例模式(饿汉懒汉)

news2024/11/17 14:34:56

目录

前言:

单线程下的单例模式

饿汉模式

懒汉模式

多线程下的单例模式

懒汉模式的修改

1.加锁

2.有条件的加锁

3.解决内存可见性和指令重排序


前言:

本片文章介绍设计模式中的一个模式——单例模式。

单例模式就是只允许创建出一个实例的类。比如之前在使用JDBC编程的时候的DataSource这个类,就可以使用单例模式。见这篇文章http://t.csdn.cn/uq1lR。

其中单例模式有很多种实现方法,这里只用懒汉模式和饿汉模式来实现单例模式。


单线程下的单例模式

单线程中,没有线程安全问题,其代码会简单很多。

饿汉模式

饿汉模式体现出一个字——急。因为这个实例直接就是在类加载阶段就被创建出来。

class SingletonHungry{

    // 用static修饰,这样在类加载阶段就有了这个实例
    private static SingletonHungry instance = new SingletonHungry();

    // 用静态公开方法返回实例
    public static SingletonHungry getInstance() {
        return instance;
    }

    // 为了防止实例化多个对象,把构造方法用private修饰
    private SingletonHungry(){};

}

public class SingletonTest1 {

    public static void main(String[] args) {

        SingletonHungry instance1 = SingletonHungry.getInstance();
        SingletonHungry instance2 = SingletonHungry.getInstance();
        System.out.println(instance1 == instance2);

        //SingletonHungry instance3 = new SingletonHungry();

    }

}

 

 


懒汉模式

懒汉模式突出一个字——懒。这个实例是只有调用获取实例方法的时候才创建出来。

class SingletonLazy{
    private static SingletonLazy instance = null;

    // 只有在调用了该方法后才创造出了实例
    public static SingletonLazy getInstance() {
        // 如果已经创建了该实例,就直接返回之前的实例
        if (instance == null) {
            instance =  new SingletonLazy();
        }
        return instance;
    }

    // 为了防止实例化多个对象,把构造方法用private修饰
    private SingletonLazy(){}
}

public class SingletonTest2 {

    public static void main(String[] args) {

        SingletonLazy instance1 = SingletonLazy.getInstance();
        SingletonLazy instance2 = SingletonLazy.getInstance();
        System.out.println(instance1 == instance2);

        //SingletonLazy instance3 = new SingletonLazy();
    }

}

代码结果如上。 


多线程下的单例模式

在上述代码中,如果考虑多线程的话

饿汉模式没有线程安全问题,它直接就是在类加载是创建出了一个实例,使用该实例也没有其他修改的操作,直接返回即可。

懒汉模式是有线程安全问题。它又要判断比较实例是否为null,又要创建一个实例,最后才返回实例。其中对于实例是由修改的操作的。只要有修改操作,就可能会有线程安全问题。如下图:

懒汉模式的修改

1.加锁

对于这种又有读,又有写的操作,保持原子性——加锁即可。

    public SingletonThread getInstance() {
        // 这里对于load cmp new这几步加锁,保持了其原子性
        synchronized (SingletonThread.class) {
            if (instance == null) {
                instance = new SingletonThread();
            }
        }
        return instance;
    }

2.有条件的加锁

但是加锁是一种开销比较大的操作,上述加锁操作并不是每次都要加锁的。如果已经创建了实例,直接返回实例即可。

    public SingletonThread getInstance() {
        // 如果实例未被创建,用加锁的方法创建实例
        // 如果创建,直接返回
        if (instance == null) {
            // 这里对于load cmp new这几步加锁,保持了其原子性
            synchronized (SingletonThread.class) {
                if (instance == null) {
                    instance = new SingletonThread();
                }
            }
        }
        return instance;
    }

3.解决内存可见性和指令重排序

内存可见性:因为instance要读取并修改,所以对于内存可见性的问题也要预防。

指令重排序:

上面的new实例的指令又分为三个顺序步骤:

①申请内存空间

②调用构造方法,实例化一个对象

③把内存空间的地址赋值给这个对象

这几步可能可能会变成①③②。单线程下没有问题,但是多线程就会有问题了。

要想解决这两个问题,使用volatile关键字修饰instance即可。

    private volatile static SingletonThread instance = null;

完整的懒汉模式的线程安全代码如下:

// 修改懒汉模式,使其线程安全
class SingletonThread {
    // 使用volatile解决内存可见性和指令重排序问题
    private volatile static SingletonThread instance = null;

    public SingletonThread getInstance() {
        // 如果实例未被创建,用加锁的方法创建实例
        // 如果创建,直接返回
        if (instance == null) {
            // 这里对于load cmp new这几步加锁,保持了其原子性
            synchronized (SingletonThread.class) {
                if (instance == null) {
                    instance = new SingletonThread();
                }
            }
        }
        return instance;
    }

}

有什么问题评论区指出。希望可以帮到你。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/173203.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

离散数学-图论-树(13)

树 1 无向树及其性质 定义1&#xff1a;连通无回路的无向图称为无向树,简称树.每个连通分支都是树的无向图称为森林.平凡图称为平凡树.在无向树中,悬挂顶点称为树叶,度数大于或等于2的顶点称为分支点. 定义2 设G<V,E>是n阶m条边的无向图&#xff0c;则下面各命题是等价…

c语言attribute关键字参数(详细)总结附示例快速掌握

目录一、简介二、参数详解2.1 section&#xff1a;自定义段2.2 aligned&#xff1a;对齐2.3 packed&#xff1a;对齐2.4 format&#xff1a;检查函数变参格式2.5 used2.6 unused2.7 at 绝对定位2.8 constructor2.9 destructor2.10 weak&#xff1a;弱声明2.11 alias&#xff1a…

macOS spotlight 聚焦 搜索范围自定义

文章目录Intro禁用不需要的查找范围&#xff0c;减少 spotlight 工作量/资源损耗搜索结果中的每个分类各自代表什么&#xff1f;Intro MBA升级系统之后&#xff0c;第一次充满电用了12h&#xff0c;之后的使用过程中掉电也很快。 新版本信息&#xff1a;macOS Ventura 13.1 (2…

I.MX6ULL裸机开发笔记1:启动方式

目录 启动模式设置步骤 1、三大模式 2.选择内部介质 3.选择接口编号 4.介质属性 原理图 芯片手册截图 开机相关全部引脚 启动设置表 启动模式设置步骤 1、三大模式 熔丝模式&#xff1a;烧录一次&#xff0c;发布产品外部模式&#xff1a;USB、串口等内部&#xff1a…

Windows系统下利用Anaconda搭建MXNet框架

1、mxnet MXNet 是一个深度学习库&#xff0c;类似于Theano 和 TensorFlow。最近想搞下深度学习&#xff0c;于是便安装mxnet。之前安装过TensorFlow&#xff0c;也踩了很多坑&#xff0c;可谓是历经波折。有的时候&#xff0c;配置环境真的是一门玄学。 2、关于网上的一些教…

手把手教你学习单片机-硬件基础知识

去耦电容的应用 C16 和 C19 起到的作 用是一样的,C10 的作用和他们两个不一样。 容值比较大的电容,理论上可以理解成水缸或者水池子,同时,大家可以直接把电流理 解成水流。 作用一,缓冲作用。当上电的瞬间,电流从电源处流下来的时候,不稳定,容易冲击电 子器件,加个…

基于云的文档管理系统——随时随地办公

如果您正在建立现代数字业务&#xff0c;您需要灵活地移动和分配您的劳动力。 DocuWare 移动劳动力解决方案可帮助您构建新的生产力模式&#xff1a;随时随地、任何设备。 毫不费力地捕捉、即时访问、始终安全 DocuWare 文档管理和工作流程自动化意味着当前流程的业务信息。 访…

【shell教程】| 简介及基本使用案例

文章目录一、简介二、脚本1 格式2 执行方式3 变量自定义变量特殊变量4 运算符5 条件判断6 流程控制1 if判断2 case语句3 for循环4 while 循环七、read读取控制台输入八、函数1 basename2 dirname3 自定义函数九、正则表达式十、文本处理工具1 cut2 grep3 sed4 awk一、简介 常见…

在线支付系列【1】支付演变史

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 文章目录支付货币发展史物物交换实物货币纸质货币电子货币数字货币支付模式演变一方支付&#xff08;现金当面支付&#xff09;二方支付&#xff08;商家银行&#xff09;第三方支付&#xff08;商家、银…

【GD32F427开发板试用】工业级串口OTA实现----移植韦东山老师BootLoader项目

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;足球之路 一、综述 一款完善的工业产品往往需要支持在线更新程序的需求&#xff0c;业界最近火热的叫法叫做“OTA”。这篇文章记录我利用技术…

2001-2020年中国区域创新能力总、分指标效用值

中国区域创新能力总、分指标效用值2001-2020 1、时间&#xff1a;2001-2020年 2、范围&#xff1a;全国31个省份 3、来源&#xff1a;中国区域创新能力评价BG 4、指标包括&#xff1a; 区域创新能力综合效用值、知识创造效用值、知识获取效用值、企业创新效用值、创新环境…

《Composing Programs》(SICP python版) chap1 笔记(2)

《Composing Programs》(SICP python版) chap1 笔记(2) 文章目录《Composing Programs》(SICP python版) chap1 笔记(2)Chapter 1: Building Abstractions with Functions1.3 Defining New Functions1.3.1 EnvironmentsFunction Signatures&#xff08;看语境翻译为函数原型比较…

【论文翻译】ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation

【论文】https://arxiv.org/abs/2204.12484v3 【github】GitHub - ViTAE-Transformer/ViTPose: The official repo for [NeurIPS22] "ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation" and [Arxiv22] "ViTPose: Vision Transformer F…

IO流操作

文章目录一、字符集常见字符集编码、解码操作二、IO流FileInputStreamFileOutputStreamFileReaderFileWriter常见问题一、字符集 常见字符集 我们的计算机底层是不可以直接存储字符的&#xff0c;计算机中底层只能存储二进制(0、1)&#xff0c;同时二进制是可以转换成十进制的…

Fluent UDF编译环境配置 VS2019

Fluent UDF编译环境配置 VS2019环境配置问题记录继续记录调试过程仅用一个host仅用一个node两个都放进去换个电脑继续报错记录错误环境配置 生成PATH文件的&#xff0c;有的没有权限在当前文件夹&#xff0c;可以用这个命令&#xff0c;还是原来的代码&#xff0c;就是改一下 …

趣味三角——前言和序言

目录 1. 前言 2. 序言 2.1 抄写员Ahmes&#xff0c;公元前1650年 2.2 古埃及的趣味数学 1. 前言 There is perhaps nothing which so occupies the middle position of mathematics as trigonometry. (也许&#xff0c;没有什么东西像三角学一样占据数学的中心位置…

离散数学-图论-欧拉图、哈密顿图、二部图、平面图(14)

欧拉图、哈密顿图、二部图、平面图 1 欧拉图 无向图G是欧拉图⇔\Leftrightarrow⇔G连通,且无奇度点。无向图G是半欧拉图⇔\Leftrightarrow⇔G连通,且仅有两个奇度点。有向图G是欧拉图⇔\Leftrightarrow⇔G强连通,且所有顶点的入度出度。有向图G是半欧拉图⇔\Leftrightarrow⇔…

登录时“自动填充”和“验证码”的实现

自动填充和验证码的实现需求1. 基础登录功能1.1 持久层pojo实体类&#xff1a;代理接口&#xff1a;1.2 业务层1.3 表现层login.jsp&#xff08;登陆界面&#xff09;&#xff1a;LoginServlet&#xff1a;selectAllServlet&#xff1a;brand.jsp&#xff08;登陆成功&#xff…

30.Isaac教程--Costmap规划器

Costmap规划器 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 文章目录Costmap规划器组件消息入门自定义图使用自定义地图改变规划器将 Costmap 添加到视线中将通道添加到配置Isaac SDK 中的标准导航规划器指示机器人在避开障碍物的同时采用最短…

赛意SMOM和金蝶云星空单据接口对接

赛意SMOM和金蝶云星空单据接口对接数据源系统:金蝶云星空金蝶K/3Cloud在总结百万家客户管理最佳实践的基础上&#xff0c;提供了标准的管理模式&#xff1b;通过标准的业务架构&#xff1a;多会计准则、多币别、多地点、多组织、多税制应用框架等&#xff0c;有效支持企业的运营…