JavaEE 初阶篇-深入了解单例模式(经典单例模式:饿汉模式、懒汉模式)

news2024/11/26 9:49:06

🔥博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞👍收藏⭐评论✍

文章目录

        1.0 单例模式的概述

        2.0 单例模式 - 饿汉式单例

        2.1 关于饿汉式单例的线程安全问题

        3.0 单例模式 - 懒汉式单例

        3.1 关于懒汉式单例的线程安全问题

        3.1.1 加锁 synchronized 方法

        3.1.2 双重检查锁定


        1.0 单例模式的概述

        单例模式是一种常见的设计模式,其核心思想是确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。单例模式通常用于需要全局访问点且只需要一个实例的情况。

单例特点包括:

        1)一个类只有一个实例对象。

        2)提供全局访问点,允许其对象访问这个实例。

        3)通过静态方法或静态变量实现。

常见的单例模式实现方法包括:

        1)饿汉式单例:在类加载时即创建实例。

        2)懒汉式单例:在第一次使用时创建实例。

使用单例模式的好处:

        使用单例模式可以避免多次实例化对象,节省内存资源,并且提供一个统一的访问点,方便管理和维护。

        2.0 单例模式 - 饿汉式单例

        “饿汉”顾名思义,有迫不及待的意思,看到食物就迫切想吃。因此,在类加载的时候,需要立即创建实例对象。为了保证只有一个实例对象,对外的静态对象实例需要封装起来,且对外的构造器也需要封装起来,对外有一个获取实例对象的静态方法即可。

代码如下:

public class Singleton {
    // 在类加载时即创建实例对象
    private static Singleton instance = new Singleton();

    // 将构造器设为私有,外部无法直接实例化
    private Singleton() {
    }

    // 提供一个公共的静态方法来获取实例对象
    public static Singleton getInstance() {
        return instance;
    }

    // 其他方法和属性
}

        通过这种方式,可以保证在程序运行过程中始终只有一个实例对象存在,且外部通过静态方法 getInstance() 来获取实例对象,确保了单例模式的实现。这种方式适合在程序初始化时就需要创建实例对象的情况下使用。

        2.1 关于饿汉式单例的线程安全问题

        在“饿汉式”单例模式中,由于在类加载时就创建实例对象,并且在静态变量中直接初始化实例,因此在多线程环境下是线程安全的。

        类加载过程是由类加载器负责,保证了在多线程环境下只会加载一次类,因此也只会创建一个实例对象。

        因此,如果使用“饿汉式”单例模式,在多线程环境下不需要额外的同步措施,可以保证线程安全。每个线程在访问该单例类的时候都会得到同一个实例对象,不会出现多个实例对象被创建的情况。

        3.0 单例模式 - 懒汉式单例

        当需要获取第一个实例对象的时候,才会去创建实例对象。

        为了保证该类只有一个实例对象,需要对外的构造方法封装,在还没获取实例对象的时候,将静态变量赋值为 null 。再提供一个静态方法来获取实例对象,当获取实例对象的时候,先会判断还对象的变量是否为 null ,如果为 null 时,这时候需要立即创建对象,然后返回该对象;如果实例对象的变量不为 null 时,直接方法该实例对象。

代码如下:

public class SingletonLazy {
    private static SingletonLazy singleton = null;
    //私有的构造方法
    private SingletonLazy(){

    }
    //获取实例对象的方法,变量不为 null 的时候直接返回该实例对象
    public static SingletonLazy getInstance(){
        if (singleton == null){
            singleton = new SingletonLazy();
        }
        return singleton;
    }
    //其他方法和属性

}

        3.1 关于懒汉式单例的线程安全问题

        懒汉式单例模式在多线程环境下存在安全问题,需要通过加锁等方式来解决。

        在懒汉单例模式中,实例对象在第一次被调用时才会被创建,如果这时候,多个线程同时调用 getInstance() 方法,可能会导致多个实例对象被创建,破环了单例的特性。

解决方法:可以通过加锁方式来确保线程安全

        3.1.1 加锁 synchronized 方法

        在 getInstance() 方法上加上 synchronized 关键字,确保在多线程环境下只有一个线程可以进入该方法,保证只创建一个实例对象。但是这种方式会影响性能,因为每次调用 getInstance() 都需要获取锁。

代码如下:

public class SingletonLazy {
    private static SingletonLazy singleton = null;
    //私有的构造方法
    private SingletonLazy(){

    }
    //获取实例对象的方法,变量不为 null 的时候直接返回该实例对象
    public static synchronized SingletonLazy getInstance(){
        if (singleton == null){
            singleton = new SingletonLazy();
        }
        return singleton;
    }
    //其他方法
    public void fun(){
        System.out.println("懒汉单例模式");
    }
}

        在静态方法 getInstance() 方法上加上了 synchronized 修饰。每当多线程抢占获取锁的时候,没有获取锁的线程需要阻塞等待。这就保证了线程安全问题。

        3.1.2 双重检查锁定

        从代码执行效率这方面来看,每一个获取实例对象的时候,都需要阻塞等待,且只有创建对象的时候才需要真正的用到锁这个作用,其余大部分不需要来创建实例对象,只需要获取实例对象。

        在 getInstance() 方法中进行双重检查,先判断实例是否已经被创建,如果没有再进行加锁创建实例。这种方式可以减少加锁的次数,提高性能。

优化代码如下:

public class SingletonLazy {
    private static volatile SingletonLazy singleton = null;
    //私有的构造方法
    private SingletonLazy(){

    }
    //获取实例对象的方法,变量不为 null 的时候直接返回该实例对象
    public static SingletonLazy getInstance(){
        if (singleton == null){
            synchronized (SingletonLazy.class){
                if (singleton == null){
                    singleton = new SingletonLazy();
                }
            }
        }
        return singleton;
    }
    //其他方法
    public void fun(){
        System.out.println("懒汉单例模式");
    }
}

        第一个 if 判断是否要加锁,实例化之后,线程自然安全,就无需加锁了,实例化之前, new 之前,就应该加锁。

        第二个 if 判断是否要创建对象。

        通过双重 if 避免了不可重复读带来的负面影响,避免了重复创建对象。

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

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

相关文章

Java | Leetcode Java题解之第4题寻找两个正序数组的中位数

题目&#xff1a; 题解&#xff1a; class Solution {public double findMedianSortedArrays(int[] A, int[] B) {int m A.length;int n B.length;if (m > n) { return findMedianSortedArrays(B,A); // 保证 m < n}int iMin 0, iMax m;while (iMin < iMax) {int…

枚举---算法

1、定义 枚举算法&#xff1a;也称之为穷举算法&#xff0c;这种算法就是在解决问题的时候去使用所有的方式去解决这个问题&#xff0c;会通过推理去考虑事件发生的每一种可能&#xff0c;最后推导出结果。优点&#xff1a;简单粗暴&#xff0c;它暴力的枚举所有可能&#xff…

每天五分钟计算机视觉:使用神经网络完成人脸的特征点检测

本文重点 我们上一节课程中学习了如何利用神经网络对图片中的对象进行定位,也就是通过输出四个参数值bx、by、bℎ和bw给出图片中对象的边界框。 本节课程我们学习特征点的检测,神经网络可以通过输出图片中对象的特征点的(x,y)坐标来实现对目标特征的识别,我们看几个例子。…

低噪声、轨至轨运算放大器芯片—— D721、D722、D724,适合用于音频领域

应用领域 D721、D722、D724是我们推荐的三款低噪声、轨至轨运算放大器芯片&#xff0c;其中D721为单运放&#xff0c;D722为双运放&#xff0c;D724为四运放。适合用于音频领域、传感器等的信号放大处理&#xff0c;比如K歌宝、音响、测距、滤波器、AD转换器前级信号处理等等。…

通过开发板来学习ROS2 21讲(基础环境配置)

通过开发板来学习ROS2 21讲&#xff08;基础环境配置&#xff09; 简介 ROS2 21讲是古月居倾力打造的ROS2 的入门学习视频&#xff0c;相信有很多小伙伴也是通过ROS2 21讲入门的ROS2。在学习过程中&#xff0c;大家有可能是使用虚拟机/PC机来运行ROS2上的案例&#xff0c;但是…

在SpringCloud2023中使用openfeign进行远程调用

你好&#xff0c;这里是codetrend专栏“SpringCloud2023实战”。 前言 feign之前是Netflix的一个子项目&#xff0c;由于停止了维护&#xff0c;spring继续维护了一个openfeign作为替代。Spring Cloud OpenFeign 具有以下优点&#xff1a; 简化微服务之间的调用&#xff0c;…

是否应该升级到ChatGPT 4.0?深度对比ChatGPT 3.5与4.0的差异

如果只是想简单地体验AI的魅力&#xff0c;感受大模型的独特之处&#xff0c;或是玩一玩文字游戏&#xff0c;那么升级至ChatGPT 4.0可能并非必需。然而&#xff0c;若你期望将AI作为提升工作学习效率的得力助手&#xff0c;那么我强烈建议你升级到ChatGPT 4.0。 如果你不知道…

【linux】lsof命令使用

1. 功能 lsof list open files, 列出被进程所使用的文件名称。 2. 基础语法 3. 参数含义 参数含义-a过滤出多个选项要同时满足的文件-U仅列出UNIX-like系统的socket文件类型。-u指定用户&#xff0c;比如-u atiaisi&#xff0c;会把用户atiaisi相关的进程使用的文件列出来。…

辽宁梵宁教育:设计领域的靠谱正规线上教育机构典范

辽宁梵宁教育&#xff0c;作为一家专注于学习设计的线上教育机构&#xff0c;近年来在业界崭露头角&#xff0c;赢得了广大学习者的认可和好评。接下来&#xff0c;本文将从多个维度详细阐述梵宁教育为何是一家靠谱且正规的线上教育机构。 梵宁教育在师资力量上表现出色。其拥有…

如何一键展示全平台信息?Python手把手教你搭建自己的自媒体展示平台

前言 灵感源于之前写过的Github中Readme.md中可以插入自己的js图片和动态api解析模块&#xff0c;在展示方面十分的美观&#xff1a; 这方面原理可以简化为&#xff0c;在Markdown中&#xff0c;你可以使用HTML标签来添加图像&#xff0c;就像这样&#xff1a; <tr><…

YOLOv9改进策略 :IoU优化| Inner-IoU基于辅助边框的IoU损失,高效结合新型边界框相似度度量(MPDIoU)| 二次创新

💡💡💡本文独家改进:Inner-IoU引入尺度因子 ratio 控制辅助边框的尺度大小用于计算损失,新型边界框相似度度量(MPDIoU)MPDIoU损失进行有效结合 💡💡💡适用场景:小目标数据集,进一步提升检测精度,强烈推荐 《YOLOv9魔术师专栏》将从以下各个方向进行创新: …

使用Flutter混淆技术保护应用隐私与数据安全

在移动应用开发中&#xff0c;保护应用代码安全至关重要。Flutter 提供了简单易用的混淆工具&#xff0c;帮助开发者在构建 release 版本应用时有效保护代码。本文将介绍如何在 Flutter 应用中使用混淆&#xff0c;并提供了相关的操作步骤和注意事项。 &#x1f4dd; 摘要 本…

酷得智能 提供多类型IC采购服务及全国性的方案开发定制

东莞市酷得智能科技有限公司成立于广东省东莞市松山湖高新产业园区&#xff0c;我们专注于电子类方案开发设计&#xff0c;提供多类型的IC采购服务。 方案定制服务包括以下几个方面&#xff1a; 功能定制&#xff1a;根据客户需求&#xff0c;我们可以为其定制各种有趣、富有挑…

存内计算是否可以应用于边缘计算

本篇文章聚焦存内计算应用&#xff0c;我们将从云边端计算各有优势出发&#xff0c;围绕边缘计算场景已有落地、赋能边缘计算存&#xff0c;算大有可为三个方面展开介绍&#xff0c;并围绕存算与边缘计算的结合应用展开构想与展望。 一.云边端计算 各有优势 云边端&#xff0…

游戏引擎架构01__引擎架构图

根据游戏引擎架构预设的引擎架构来构建运行时引擎架构 ​

【THM】SQL Injection(SQL注入)-初级渗透测试

简介 SQL(结构化查询语言)注入,通常称为 SQLi,是对 Web 应用程序数据库服务器的攻击,导致执行恶意查询。当 Web 应用程序使用未经正确验证的用户输入与数据库进行通信时,攻击者有可能窃取、删除或更改私人数据和客户数据,并攻击 Web 应用程序身份验证方法以获取私有数据…

Spring AOP + 自定义注解 实现公共字段的填充

Spring AOP 自定义注解 实现公共字段的填充 代码冗,不利于后期维护. 定义操作这些字段的方法类型 实现步骤&#xff1a; 自定义注解AutoFill,用于表示操作这些公共字段的方法自定义切面类AutoFillAspect,统一拦截&#xff0c;通过反射获取方法入参&#xff0c;并填充公共字段…

一个很变态,但能快速掌握软考高项的野路子

软考已经迫在眉睫&#xff0c;今天给各位整理了软考高项 信息系统项目管理师 的重要知识点口诀&#xff0c;只要大家能把这些都背下来&#xff0c;对你们掌握高项事倍功效&#xff0c;赶紧行动起来吧 2024年上半年信息系统项目管理师知识点口诀汇总 一、IT部分 智慧城市5个核心…

爬虫逆向实战(39)-某某兔装修网登陆(RSA)

一、数据接口分析 主页地址&#xff1a;某某兔装修网 1、抓包 通过抓包可以发现登陆是表单提交 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块&#xff0c;可以发现有一个val和password的加密参数 请求头是否加密&#xff1f; 无响应是否加密…

RK3568驱动指南|第十四篇 单总线-第158章DS18B20编写字符设备驱动框架

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…