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

品读 Java 经典巨著《Effective Java》90条编程法则,第3条:用私有构造器或者枚举类型强化Singleton属性

《Effective Java》中的第3条编程法则主要是针对在开发过程如何实现单例模式,作者 Joshua Bloch 在书中给出了3种单例模式的实现方式:私有构造器和公有静态域、私有构造器和公有静态方法、枚举式。

什么是单例模式?

单例模式是一种设计模式,旨在确保一个类只有一个实例,其主要目的是控制类的实例化过程,避免创建多个对象实例;并提供一个全局访问点来获取该实例。这种模式适用于需要唯一对象来协调全局操作或资源管理的场景,例如配置管理器、线程池等。

单例实现方式

实现方式一:私有构造器和公有静态域(饿汉式单例模式)

通过私有构造器和公有静态域实现单例模式是一种简单且直接的方法,这种实现通常被称为饿汉式单例模式

public class Singleton {// 单例对象,在类加载时创建public static final Singleton INSTANCE = new Singleton();// 私有构造器,防止外部实例化private Singleton() {// 可以添加初始化代码}// 其他方法public void doSomething() {// 实现具体的业务逻辑}
}

在这种实现中,通过将构造器设为 private,类外部无法直接创建实例,从而确保了单例模式的唯一性。而 static final 修饰符确保了在类加载阶段就创建并初始化实例,并且实例一旦创建后不可变,这样就进一步保证了单例实例的唯一性和一致性。整体设计既简单又有效。

实现方式二:私有构造器和公有静态方法(懒汉式单例模式 & 双重检查锁定)

私有构造器和公有静态方法的实现通常称为懒汉式单例模式

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

相比饿汉式单例模式实例的创建时机固定,懒汉式的实现将实例的初始化延迟到在第一次调用 getInstance 方法时创建,这样可以避免在程序启动时就初始化实例,从而节省资源。

但是在懒汉式的实现中,使用了synchronized 关键字保证在多线程环境下对 getInstance 方法的访问是线程安全的。然而,这种实现方式的缺点是每次调用 getInstance 方法时都要进行同步,这会带来性能开销。

幸运的是,由于我们使用静态工厂方法创建类的实例,那么我们就可以在方法种控制创建实例的时机,即在懒汉式单例模式的基础上进行优化,减少同步的开销来提高效率:

  1. 在获取实例时,首先检查实例是否已存在,如果已存在,则直接返回该实例。
  2. 如果实例不存在,再进行同步检查,以确保实例初始化的线程安全。
public class Singleton {// 使用 volatile 关键字确保线程安全private static volatile Singleton instance;// 私有构造器防止外部实例化private Singleton() {// 私有构造器}// 提供公共的静态方法获取实例public static Singleton getInstance() {if (instance == null) { // 第一次检查synchronized (Singleton.class) {if (instance == null) { // 第二次检查instance = new Singleton();}}}return instance;}
}

这种优化在获取实例时引入了两次检查,因此也被称为双重检查锁定

  • 第一次检查:在同步块外部进行,以减少不必要的同步开销。
  • 第二次检查:在同步块内部进行,以确保实例的唯一性。

实现方式三:枚举式

由于枚举类型本身设计用于定义一组常量,因此实现单例模式时,通常一个枚举类型中只定义一个枚举实例:

public enum Singleton {INSTANCE;public void doSomething() {// 实现具体功能}
}

饿汉式 VS 懒汉式 VS 枚举式

饿汉式和懒汉式单例模式的实现,在反序列化和反射攻击可能会导致创建多个实例,破坏单例模式的唯一性。因此还需要添加以下处理:

  • 实现 readResolve 方法,确保在反序列化过程中,获取的对象仍然是单例实例,而不是新的实例:

    private Object readResolve() {return getInstance();
    }
    
  • 在构造函数中增加检查,防止通过反射创建多个实例:

    private Singleton() {if (instance != null) {throw new RuntimeException("Use getInstance() method to get the single instance of this class.");}
    }
    

枚举由于自身的特殊机制,使得枚举式相比前两者更适合单例模式得实现:

  • 天然的线程安全:Java 枚举类型的实例在 JVM 加载时会创建一次且只创建一次,整个加载过程是线程安全的。因此,不需要额外的同步来保证线程安全。
  • 防止反序列化攻击:枚举的实例由 JVM 管理,序列化和反序列化过程中保持唯一性。这意味着即使序列化和反序列化操作被恶意操控,也不会生成新的实例。
  • 防止反射攻击:枚举类型的构造函数是私有的,当尝试使用反射创建枚举实例会抛出 IllegalArgumentException 异常,从而保护了单例的唯一性。

这也是 Joshua Bloch 在书中提到单元素的枚举类型经常成为实现 Singleton 的最佳方法的原因。

相关文章:

品读 Java 经典巨著《Effective Java》90条编程法则,第3条:用私有构造器或者枚举类型强化Singleton属性

《Effective Java》中的第3条编程法则主要是针对在开发过程如何实现单例模式,作者 Joshua Bloch 在书中给出了3种单例模式的实现方式:私有构造器和公有静态域、私有构造器和公有静态方法、枚举式。 什么是单例模式? 单例模式是一种设计模式…...

如何在Flask中处理表单数据

在Flask中处理表单数据是一个常见的任务,它涉及从客户端接收数据并在服务器端进行解析和处理。Flask本身不直接提供表单验证的功能,但它可以与WTForms等库结合使用来简化表单处理过程。不过,即使没有WTForms,你仍然可以直接通过Fl…...

9月12日的学习

练习 #include "widget.h" #include "ui_widget.h" QListWidgetItem *p; Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget),socket(new QTcpSocket(this))//给客户端指针实例化空间及关联父组件 {ui->setupUi(this);//初始化,ui-…...

Java架构师未来篇大模型

目录 1. 大模型的定义2 大模型相关概念区分3 大模型的发展历程4. 大模型的特点5 大模型的分类6 大模型的泛化与微调7 大模型岗位需求8 理解大模型8.1 生活中的比喻8.2 大模型的定义9 大模型工作9.1 数据的积累9.2 模型的训练9.3 预测和应用10 大模型的实际应用10.1 语言处理10.…...

11.5.软件系统分析与设计-面向对象的程序设计与实现

面向对象的程序设计与实现 设计模式 Java代码 C代码...

中电金信:金融级数字底座“源启”:打造新型数字基础设施 筑牢千行百业数字化转型发展基石

近期,金融级数字底座“源启”登录中国电子《最轻大国重器》融媒体报道。从数字底座到数智底座,从金融行业到千行百业,“源启”用数智化转型的中国电子解决方案,为全球企业转型及安全发展提供强大动能。 立足中国电子科技创新成果&…...

IDEA怎么让控制台自动换行

IDEA怎么让控制台自动换行 操作流程 菜单>File>Settings>Editor>General>Console>勾选Use soft wraps in console 换行效果...

大模型笔记02--基于fastgpt和oneapi构建大模型应用平台

大模型笔记02--基于fastgpt和oneapi构建大模型应用平台 介绍部署&测试部署fastgptoneapi服务部署向量模型m3e和nomic-embed-text测试大模型 注意事项说明 介绍 随着大模型的快速发展,众多IT科技厂商都开发训练了各自的大模型,并提供了各具特色的AI产…...

linux-用户与权限管理-组管理

在 Linux 系统中,用户、组与权限管理是保障系统安全的重要机制。用户和组的管理不仅涉及对系统资源的访问控制,还用于权限的分配和共享。组管理在 Linux 中尤其重要,它能够帮助管理员组织用户并为不同的组分配特定权限,从而控制用…...

Day23_0.1基础学习MATLAB学习小技巧总结(23)——句柄图形

利用空闲时间把碎片化的MATLAB知识重新系统的学习一遍,为了在这个过程中加深印象,也为了能够有所足迹,我会把自己的学习总结发在专栏中,以便学习交流。 参考书目:《MATLAB基础教程 (第三版) (薛山)》 之前的章节都是…...

同步io和异步io

同步 I/O 和异步 I/O 是处理输入输出操作的两种不同策略,它们各有优缺点,适用于不同的场景。下面是它们的主要区别: 同步 I/O 定义:在同步 I/O 模型中,发起 I/O 操作的线程会被阻塞,直到操作完成。换句话说…...

AI基础 L19 Quantifying Uncertainty and Reasoning with Probabilities I 量化不确定性和概率推理

Acting Under Uncertainty 1 Reasoning Under Uncertainty • Real world problems contain uncertainties due to: — partial observability, — nondeterminism, or — adversaries. • Example of dental diagnosis using propositional logic T oothache ⇒ C av ity • H…...

C++ 关于时间的轮子

时间字符串转chrono::system_clock std::chrono::system_clock::time_point parse_date(const std::string& date_str) {std::tm tm {};std::istringstream ss(date_str);ss >> std::get_time(&tm, "%Y-%m-%d"); // 假设日期字符串格式为YYYY-MM-DDr…...

阿里达摩院:FunASR - onnxruntime 部署

阿里达摩院:FunASR - onnxruntime 部署 git clone https://github.com/alibaba/FunASR.git 切换到 onnxruntime cd FunASR/runtime/onnxruntime1下载 onnxruntime wget https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/dep_libs/onnxruntime-linux-x64-1.14.0.t…...

SpringMvc注解

SpringMvc注解 1 SpringMcv基础环境搭建 注&#xff1a;如果已经有SpringMvc项目直接跳过这个就可以了 1 新建项目 2.修改文件为packaging 为war包 <packaging>war</packaging> <?xml version"1.0" encoding"UTF-8"?> <pr…...

队列的基本概念及顺序实现

队列的基本概念 队列的定义 ​ 队列(Queue)简称队&#xff0c;也是一宗操作受限的线性表&#xff0c;只允许在表的一段进行插入&#xff0c;而在表的另一端进行删除。向队列中插入元素成为入队或进队&#xff1b;删除元素成为出队或离队。 ​ 特性&#xff1a;先进先出 (Fir…...

Leetcode 最长连续序列

算法流程&#xff1a; 哈希集合去重&#xff1a; 通过将数组中的所有元素放入 unordered_set&#xff0c;自动去除重复元素。集合的查找操作是 O(1)&#xff0c;这为后续的快速查找提供了保证。 遍历数组&#xff1a; 遍历数组中的每一个元素。对于每个元素&#xff0c;首先检…...

linux网络编程——UDP编程

写在前边 本文是B站up主韦东山的4_8-3.UDP编程示例_哔哩哔哩_bilibili视频的笔记&#xff0c;其中有些部分博主也没有理解&#xff0c;希望各位辩证的看。 UDP协议简介 UDP 是一个简单的面向数据报的运输层协议&#xff0c;在网络中用于处理数据包&#xff0c;是一种无连接的…...

第四部分:1---文件内核对象,文件描述符,输出重定向

目录 struct file内核对象&#xff1a; 如何读写文件&#xff1f; 文件描述符在文件描述符表中的分配规则&#xff1a; 输出重定向初步解析&#xff1a; dup2实现复制文件描述符&#xff1a; struct file内核对象&#xff1a; struct file 是在内核空间中创建的用于描述文…...

如何在开发与生产环境中应用 Flask 进行数据库管理:以 SQLAlchemy 和 Flask-Migrate 为例

在使用 Flask 进行开发时&#xff0c;数据库管理是一个至关重要的环节。借助 SQLAlchemy 作为 ORM&#xff08;对象关系映射&#xff09;工具和 Flask-Migrate 进行数据库迁移&#xff0c;开发者可以高效地进行数据库管理&#xff0c;并在不同的环境&#xff08;如开发环境和生…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...