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

Java设计模式之单例模式详解(懒汉式和饿汉式)

在开发工作中,有些类只需要存在一个实例,这时就可以使用单例模式。Java中的单例模式是一种常见的设计模式,它确保一个类只有一个实例,并提供全局访问点。下面来介绍一下两种常见的单例模式:懒汉式和饿汉式。

一、懒汉式

懒汉式属于一种延迟加载的单例模式,它的特点是在第一次使用时创建实例对象,而不是在类加载时就创建。

1.1 代码示例

public class LazySingleton {private static LazySingleton instance;private LazySingleton() {// 私有构造方法}public static synchronized LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}

在代码中,我把构造函数声明为私有的,以防止其他类直接通过构造函数创建实例对象。
getInstance() 方法是获取实例对象的入口。在该方法内部,首先检查实例对象 instance是否已经被创建。如果实例对象为 null,表示还没有创建过,就通过调用构造函数来创建实例对象。如果已经创建过,就直接返回已有的实例对象。

为了保证线程安全,在 getInstance() 方法上添加了 synchronized 关键字,使得在多线程环境下只有一个线程能够进入创建实例。保证了多线程情况下只会创建一个实例对象。

1.2 适用场景

  1. 实例的创建和初始化需要消耗较多时间或资源时,不希望在程序启动时就加载实例。
  2. 需要延迟加载实例,只有在需要的时候才创建。
  3. 需要在不同的线程中使用单例对象。

懒汉式可以避免在不需要实例对象时的资源浪费,只有在需要时才进行创建。这种延迟加载的特性使得它在某些情况下更加高效。

下面举一个管理文件的读写操作的例子:

public class FileManager {private static FileManager instance;private File file;private FileManager() {// 初始化文件对象file = new File("D:\\file\\demo.txt");}public static synchronized FileManager getInstance() {if (instance == null) {instance = new FileManager();}return instance;}public void readFile() {// 读取文件内容并进行相应操作...}}

在上述示例中,通过懒汉式单例模式,我们可以确保在第一次调用 getInstance() 方法时才创建实例对象。其他类可以通过调用该方法获取 FileManager 的实例对象。然后,可以使用该实例对象的方法来进行文件操作,例如 readFile() 方法。这样,无论在哪个地方需要读写文件,都可以通过 FileManager.getInstance().readFile() 方法来使用文件管理器。

总的来说,懒汉式适用于在第一次使用时才进行对象创建的场景,并且在实例对象初始化过程中没有复杂的线程安全要求。文件管理器就是一个典型的例子,因为在应用程序启动时可能不需要立即读写文件,而是在需要的时候才进行相关操作。

1.3 注意事项

  1. 线程安全:懒汉式是线程安全的,因为通过给 getInstance() 方法添加 synchronized 关键字,可以保证在多线程环境下只有一个线程能够进入创建实例。但是这也带来了性能上的开销。
  2. 性能开销:由于加了锁,每次获取实例都需要进行同步控制,可能会引起一定的性能问题。如果对性能要求较高,可以考虑使用双重检查锁定(Double-Checked Locking)等方式进行改进,以减少同步开销。
  3. 可序列化:如果需要将懒汉式单例对象序列化到文件或网络中,需要注意实现 Serializable 接口,以确保对象的序列化和反序列化过程正确无误。

二、饿汉式

饿汉式是一种在类加载时就创建实例的单例模式。它的特点是无论是否会被使用到,实例对象都在类加载时被创建。

2.1 示例代码

public class EagerSingleton {private static final EagerSingleton instance = new EagerSingleton();private EagerSingleton() {// 私有构造方法}public static EagerSingleton getInstance() {return instance;}
}

在代码中,先把实例对象 instance 定义为静态的 final 变量,并在声明时就进行实例化。

因为实例对象在类加载时就被创建,所以可以保证在任何情况下都能获取到同一个实例对象。

2.2 适用场景

  1. 实例的创建和初始化过程较为简单,并且不会消耗过多的时间或资源。
  2. 希望在程序启动时就加载实例,避免在后续代码中频繁创建和初始化实例。
  3. 饿汉式能够保证在任何时候都能获取到实例对象,适用于简单的单例对象的创建和初始化。

下面举一个管理日志的例子:

public class Logger {private static final Logger instance = new Logger();private Logger() {// 初始化日志记录器}public static Logger getInstance() {return instance;}public void log(String message) {// 记录日志消息}// 其他日志操作方法...
}

上述示例中,在 Logger 类的内部,将实例对象 instance 定义为静态的 final 变量,并在声明时就进行实例化。这样,在类加载时实例对象就会被创建。然后通过提供 getInstance() 方法,其他类可以调用该方法获取 Logger 的实例对象。然后,可以使用该实例对象的方法来记录日志消息,例如 log(String message) 方法。

这样,无论在哪个地方需要记录日志,都可以通过 Logger.getInstance().log(String message) 方法来使用日志记录器。

总的来说,饿汉式适用于需要在程序启动时就初始化的资源,且在整个应用程序的生命周期中都需要使用到的场景。日志记录器就比较适合,因为日志记录功能通常需要在应用程序启动之初就准备好,并在整个应用程序的运行过程中记录日志消息。

2.3 注意事项

  1. 线程安全:饿汉式是线程安全的,因为实例对象已经在类加载时就创建好了,不存在多线程环境下的竞争问题。
  2. 性能与资源消耗:由于实例对象在类加载时就被创建,可能会导致一些性能和资源上的浪费,特别是在某些情况下实例对象并没有被使用到。

饿汉式是一种简单且直接的方式来创建单例对象,但也可能带来一些不必要的性能和资源消耗。因此,在实际应用中需要根据具体需求进行权衡和选择。

三、总结

懒汉式和饿汉式是两种常见的Java单例模式。懒汉式在第一次使用时创建实例,而饿汉式在类加载时就创建实例。需要注意的是,在实际应用中,应根据具体场景进行综合考虑和设计。选择合适的单例模式可以提高代码的可维护性和性能 ~

相关文章:

Java设计模式之单例模式详解(懒汉式和饿汉式)

在开发工作中,有些类只需要存在一个实例,这时就可以使用单例模式。Java中的单例模式是一种常见的设计模式,它确保一个类只有一个实例,并提供全局访问点。下面来介绍一下两种常见的单例模式:懒汉式和饿汉式。 一、懒汉式…...

软件测试基本知识

安全测试 安全防护策略?(漏洞扫描、入侵检查、安全日志、隔离防护) 安全日志:用于记录非法用户的登录名称、操作时间及内容等信息,以便发现问题并提出解决措施;安全日志仅记录相关信息,不对非…...

Vue项目中强制刷新页面的方法

我们在动态切换组件的过程中,导航栏和底栏不动,动态切换中间区域的情况,在首页可以进行跳转任意组件,在组件与组件之间不能相互跳转,路由发生了变化,但是页面未改变,这时我们就需要强制刷新页面…...

文件按关键字分组-切割-染色-写入excel

1. 背景 针对下面的文件data.csv,首先根据fid进行排序,然后分组,使相同fid的记录放到同一个excel文件中,并对每列重复的数据元素染上红色。 fid,user_id -1000078398032092029,230410010036537520 -1000078398032092029,23042301…...

爬虫的基本原理:爬虫概述及爬取过程

前言 随着互联网的不断发展和普及,我们的生活越来越离不开网络。而网络世界中有着海量的信息和数据,这些信息和数据对于我们的工作和生活都有很大的帮助。但是,如何高效地获取这些数据呢?这时候,爬虫这个工具就派上用…...

cocos2D插件转3D插件

cocos2D插件转3D插件 use strict;/*** 3d插件api映射,兼容2d插件* */let fs require("fs");let path require("path");let baseDir ;const prsPath (Editor.Project && Editor.Project.path ? Editor.Project.path : Editor.remote.projectP…...

[Angular] 主从表结构,从表记录在主表固定栏位上呈现

Background 主从表结构,有时为了方便数据呈现,在UI上不显示从表资料,那么需要动态把从表的资料加载到主表的固定栏位上。 例如:主表是人员信息,从表是银行卡信息,一个人在同一家银行可能有多张银行卡&…...

Kotlin Multiplatform 创建多平台分发库

目标:通过本教程学习如何使用 Kotlin Multiplatform Library 创建多平台分发库(iOS,安卓)。 创建一个项目 1、本教程使用的是Android Studio创建 2、选择 新建工程,选择 Kotlin Multiplatform Library 3、点击next 输入需要创建的项目名称以…...

[SQL挖掘机] - union/union all 使用注意事项

因为当使用union和union all操作符时,有一些注意事项需要考虑: 1. 列数和数据类型匹配: 要使用union或union all合并结果集,两个或多个查询的 select 语句必须返回相同数量和类型的列。确保每个查询返回相同的列数,并…...

php 单例模式

1&#xff0c;单例模式&#xff0c;属于创建设计模式&#xff0c;简单来说就是一个类只能有一个实例化对象&#xff0c;并提供一个当前类的全局唯一可访问入口&#xff1b; 2&#xff0c;例子 <?phpclass Singleton {private static $instance null;// 禁止被实例化priva…...

【数据结构】实验二:顺序表

实验二 顺序表 一、实验目的与要求 1&#xff09;熟悉顺序表的类型定义&#xff1b; 2&#xff09;熟悉顺序表的基本操作&#xff1b; 3&#xff09;灵活应用顺序表解决具体应用问题。 二、实验内容 1&#xff09;在一个整数序列a1,a2,…,an中&#xff0c;若存在一个数&…...

【高级数据结构】线段树

目录 最大数&#xff08;单点修改&#xff0c;区间查询&#xff09; 线段树1&#xff08;区间修改&#xff0c;区间查询&#xff09; 最大数&#xff08;单点修改&#xff0c;区间查询&#xff09; 洛谷&#xff1a;最大数https://www.luogu.com.cn/problem/P1198 题目描述 …...

qt简易闹钟

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);ui->stopBtn->setDisabled(true);this->setFixedSize(this->size()); //设置固定大小this->s…...

python和c加加有什么区别,c和c++和python先学哪个

本篇文章给大家谈谈c加加编程和python编程有什么区别&#xff0c;以及python和c加加有什么区别&#xff0c;希望对各位有所帮助&#xff0c;不要忘了收藏本站喔。 1、python和c学哪个好 学C好。 C通常比Python更快&#xff0c;因为C是一种编译型语言&#xff0c;而Python则是…...

Visual Studio 2022 cmake配置opencv开发环境

1. 环境与说明 这里我用的是 widnows 10 64位&#xff0c;Visual Studio 用的 Visual Studio Community 2022 (社区版) 对于Android开发工程师来说&#xff0c;为什么要使用Visual Studio 呢 ? 因为在Visual Studio中开发调试OpenCV方便&#xff0c;可以开发调试好后&#xf…...

C++ GDAL找出多时相遥感影像缺失的日期并自动生成新的全零图像作为替补

本文介绍基于C 语言的GDAL库&#xff0c;基于一个存储大量遥感影像的文件夹&#xff0c;依据每一景遥感影像的文件名中表示日期的那个字段&#xff0c;找出这些遥感影像中缺失的成像日期&#xff0c;并新生成多个像元值全部为0的栅格文件&#xff0c;作为这些缺失日期当日的遥感…...

【AI底层逻辑】——篇章5(下):机器学习算法之聚类降维时间序列

续上&#xff1a; 目录 4、聚类 5、降维 6、时间序列 三、无完美算法 往期精彩&#xff1a; 4、聚类 聚类即把相似的东西归在一起&#xff0c;与分类不同的是&#xff0c;聚类要处理的是没有标签的数据集&#xff0c;它根据样本数据的分布特性自动进行归类。 人在认知是…...

P1980 [NOIP2013 普及组] 计数问题

[NOIP2013 普及组] 计数问题 题目描述 试计算在区间 1 1 1 到 n n n 的所有整数中&#xff0c;数字 x x x&#xff08; 0 ≤ x ≤ 9 0\le x\le9 0≤x≤9&#xff09;共出现了多少次&#xff1f;例如&#xff0c;在 1 1 1 到 11 11 11 中&#xff0c;即在 1 , 2 , 3 , 4…...

需求管理全过程流程图及各阶段核心关注点详解

分析报告指出&#xff0c;多达76%的项目失败是因为差劲的需求管理&#xff0c;这个是项目失败的最主要原因&#xff0c;比落后的技术、进度失控或者混乱的变更管理还要关键。很多项目往往在开始的时候已经决定了失败&#xff0c;谜底就在谜面上&#xff0c;开始就注定的失败&am…...

Android开源 自定义emoji键盘,EmojiPack v2.1版本

目录 一&#xff0c;简介 二、安装 添加jitpack 仓库 添加依赖: 混淆规则: 三、使用 1、一次性配置emoji显示处理 二、emoji的自定义键盘的使用 一&#xff0c;简介 EmojiPack当前已提供emoji的显示和emoji的选择自定义键盘&#xff0c;在emoji显示这一方面&#xff0…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

02.运算符

目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&&#xff1a;逻辑与 ||&#xff1a;逻辑或 &#xff01;&#xff1a;逻辑非 短路求值 位运算符 按位与&&#xff1a; 按位或 | 按位取反~ …...

麒麟系统使用-进行.NET开发

文章目录 前言一、搭建dotnet环境1.获取相关资源2.配置dotnet 二、使用dotnet三、其他说明总结 前言 麒麟系统的内核是基于linux的&#xff0c;如果需要进行.NET开发&#xff0c;则需要安装特定的应用。由于NET Framework 是仅适用于 Windows 版本的 .NET&#xff0c;所以要进…...

【版本控制】GitHub Desktop 入门教程与开源协作全流程解析

目录 0 引言1 GitHub Desktop 入门教程1.1 安装与基础配置1.2 核心功能使用指南仓库管理日常开发流程分支管理 2 GitHub 开源协作流程详解2.1 Fork & Pull Request 模型2.2 完整协作流程步骤步骤 1: Fork&#xff08;创建个人副本&#xff09;步骤 2: Clone&#xff08;克隆…...

【工具教程】多个条形码识别用条码内容对图片重命名,批量PDF条形码识别后用条码内容批量改名,使用教程及注意事项

一、条形码识别改名使用教程 打开软件并选择处理模式&#xff1a;打开软件后&#xff0c;根据要处理的文件类型&#xff0c;选择 “图片识别模式” 或 “PDF 识别模式”。如果是处理包含条形码的 PDF 文件&#xff0c;就选择 “PDF 识别模式”&#xff1b;若是处理图片文件&…...

Spring事务传播机制有哪些?

导语&#xff1a; Spring事务传播机制是后端面试中的必考知识点&#xff0c;特别容易出现在“项目细节挖掘”阶段。面试官通过它来判断你是否真正理解事务控制的本质与异常传播机制。本文将从实战与源码角度出发&#xff0c;全面剖析Spring事务传播机制&#xff0c;帮助你答得有…...

二维数组 行列混淆区分 js

二维数组定义 行 row&#xff1a;是“横着的一整行” 列 column&#xff1a;是“竖着的一整列” 在 JavaScript 里访问二维数组 grid[i][j] 表示 第i行第j列的元素 let grid [[1, 2, 3], // 第0行[4, 5, 6], // 第1行[7, 8, 9] // 第2行 ];// grid[i][j] 表示 第i行第j列的…...