Java 中的单例模式

引言:

        在 Java 编程中,单例模式是一种常见的设计模式,它保证一个类只能创建一个实例,并提供一个全局访问点。单例模式在很多场景下都非常有用,比如线程池、日志系统、数据库连接池等。本文将详细介绍 Java 中单例模式的实现方式,并通过示例说明其在实际应用中的应用场景。

一、单例模式的实现方式

在 Java 中,实现单例模式有多种方式,常见的包括:

  1. 懒汉式(Lazy Initialization):在第一次调用时才创建实例。
  2. 饿汉式(Eager Initialization):在类加载时就创建实例。
  3. 双重检查锁(Double-Checked Locking):通过双重检查加锁来确保只有一个实例被创建。
  4. 静态内部类(Static Inner Class):利用类加载机制保证线程安全并且延迟加载。

下面将分别介绍这些实现方式,并给出相应的示例。

懒汉式单例模式

懒汉式单例模式在第一次调用时才创建实例,示例如下:

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

饿汉式单例模式

饿汉式单例模式在类加载时就创建实例,示例如下:

public class EagerSingleton {private static final EagerSingleton instance = new EagerSingleton();private EagerSingleton() {}public static EagerSingleton getInstance() {return instance;}
}

双重检查锁单例模式

双重检查锁单例模式通过双重检查加锁来确保只有一个实例被创建,示例如下:

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

静态内部类单例模式

静态内部类单例模式利用类加载机制保证线程安全并且延迟加载,示例如下:

public class StaticInnerClassSingleton {private StaticInnerClassSingleton() {}private static class SingletonHolder {private static final StaticInnerClassSingleton instance = new StaticInnerClassSingleton();}public static StaticInnerClassSingleton getInstance() {return SingletonHolder.instance;}
}

二、单例模式的应用场景

单例模式在很多场景下都非常有用,比如:

  • 在多线程环境下,需要确保某个类只有一个实例。
  • 对象需要被广泛访问,比如日志记录器、数据库连接池等。
  • 控制资源的使用,比如线程池、缓存等。

 

三、各个单例模式的优点和缺点 

1. 懒汉式单例模式

优点:
  • 延迟加载:在第一次调用 getInstance() 方法时才会创建实例,节省了内存资源。
  • 线程安全(通过 synchronized 关键字):在多线程环境下也能够正常工作。
缺点:
  • 性能低:由于在每次获取实例时都需要加锁,会导致性能下降。
  • 可能出现线程安全问题:在多线程环境下,由于加锁的开销较大,可能会出现多个线程同时创建实例的情况。

2. 饿汉式单例模式

优点:
  • 线程安全:由于在类加载时就创建实例,所以可以保证线程安全。
缺点:
  • 浪费内存:在应用程序启动时就创建实例,可能会造成内存浪费,尤其是在实例很大或者实例化开销很大的情况下。
  • 不能实现延迟加载:如果在应用程序启动时就创建实例,而实例的创建又很消耗资源,可能会影响应用程序的启动速度。

3. 双重检查锁单例模式

优点:
  • 延迟加载:通过双重检查加锁的方式实现延迟加载,提高了性能。
  • 线程安全:在多线程环境下也能够保证只有一个实例被创建。
缺点:
  • 实现复杂:需要考虑线程安全、对象创建和性能等多个方面的问题,容易出错。
  • 可能存在指令重排序问题:在某些情况下,可能会由于指令重排序而导致获取到未完全初始化的实例。

4. 静态内部类单例模式

优点:
  • 延迟加载:通过静态内部类的加载机制实现延迟加载,提高了性能。
  • 线程安全:在类加载时就完成了实例化,保证了线程安全。
缺点:
  • 可能存在反序列化问题:如果单例类实现了 Serializable 接口,在进行反序列化时可能会破坏单例模式。
  • 对象创建时机不可控:由于是在类加载时创建实例,因此无法控制实例创建的时机。

总结:

         在选择单例模式的实现方式时,需要根据具体的应用场景和需求综合考虑。如果需要延迟加载、并且在多线程环境下保证线程安全,可以选择双重检查锁单例模式或者静态内部类单例模式;如果希望在应用程序启动时就创建实例,并且不考虑性能问题,可以选择饿汉式单例模式;如果需要延迟加载并且希望代码简洁、安全可靠,可以选择静态内部类单例模式。在实际应用中,需要根据具体情况选择合适的单例模式实现方式,以确保程序的正确性和性能。

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

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

相关文章

操作教程|在MeterSphere中通过SSH登录服务器的两种方法

MeterSphere开源持续测试平台拥有非常强大的插件集成机制,用户可以通过插件实现平台能力的拓展,借助插件或脚本实现多种功能。在测试过程中,测试人员有时需要通过SSH协议登录至服务器,以获取某些配置文件和日志文件,或…

知乎:多云架构下大模型训练,如何保障存储稳定性?

知乎,中文互联网领域领先的问答社区和原创内容平台,2011 年 1 月正式上线,月活跃用户超过 1 亿。平台的搜索和推荐服务得益于先进的 AI 算法,数百名算法工程师基于数据平台和机器学习平台进行海量数据处理和算法训练任务。 为了提…

在 Linux中解压,压缩命令详解

在 Linux中解压,压缩命令详解 在 Linux中解压,压缩命令详解 🐧💻摘要引言正文内容解压命令详解1. 解压 .zip 文件unzip 命令 2. 解压 .tar.gz、.tar.bz2、.tar.xz 文件tar 命令 3. 解压其他格式的压缩文件gzip 命令bzip2 命令 压…

哥本哈根Major后steam搬砖该何去何从?

都在问我哥本哈根major比赛过后市场会不会崩盘呢?说实话,我是不喜欢预测市场的,其实是没那个本事而已。若真有这个预测市场走势的本事,我还用坐在这里每天苦哈哈的搬砖吗?我直接干囤卡囤号的倒卖生意岂不早发财了&…

宝塔面板与1Panel的详细对比分析

在当今的服务器管理领域,宝塔面板和1Panel都是备受欢迎的管理工具。它们各自具有独特的特点和优势,同时也存在一些局限性。本文将从多个维度对比这两款产品,帮助用户根据自身需求做出更合适的选择。 宝塔面板 优点 易用性:宝塔…

九州金榜|孩子厌学应该怎么引导?

孩子厌学,这是许多家长都可能面临的问题。对于这个问题,我们首先要明白,厌学并非孩子的错,而是他们在成长过程中所遇到的一种困境。那么,作为家长,我们应该如何引导他们走出这个困境呢?下面九州…

深入浅出:探索Hadoop生态系统的核心组件与技术架构

目录 前言 HDFS Yarn Hive HBase Spark及Spark Streaming 书本与课程推荐 关于作者: 推荐理由: 作者直播推荐: 前言 进入大数据阶段就意味着 进入NoSQL阶段,更多的是面向OLAP场景,即数据仓库、BI应用等。 …

【博弈论——2探究纳什均衡】

1.纳什均衡 纳什均衡(Nash Equilibrium),由美国数学家约翰纳什(John Nash)提出,是博弈论中的一个重要概念,用来描述在一个非合作博弈中,各个参与者在考虑了其他所有参与者策略的前提…

分享 | 顶刊高质量论文插图配色(含RGB值及16进制HEX码)(第三期)

第三期顶刊绘图配色分享来啦!这一期做的细心了一点,把双色配色、三色配色、四色配色、多色配色分开展示,大家用起来会更方便一点: 这次还是用之前写了一个多小时的提取论文图片颜色并得出RGB值和16进制码并标注在原图的代码&…

探索c++:string常用接口 迷雾

个人主页:日刷百题 系列专栏:〖C/C小游戏〗〖Linux〗〖数据结构〗 〖C语言〗 🌎欢迎各位→点赞👍收藏⭐️留言📝 ​ ​ 一、string类 这里我们对string类进行一个简单的总结: string是表示字符串的字…

矩阵间关系的建立

参考文献 2-D Compressive Sensing-Based Visually Secure Multilevel Image Encryption Scheme 加密整体流程如下: 我们关注左上角这一部分: 如何在两个图像之间构建关系,当然是借助第3个矩阵。 A. Establish Relationships Between Different Images 简单说明如下: …

R语言 | 上下双向柱状图

1. 效果图 2. 代码 # 生成测试数据 difdata.frame(labelspaste0("pathway", 1:3),upc(30,15,1),downc(10,20,40) ) rownames(dif)dif$labels dif#变形 difreshape2::melt(dif) dif# 绘图 ggplot(dif, aes(xlabels, yifelse(variable"up", value, -value), …

react 面试题(2024 最新版)

1. 对 React 的理解、特性 React 是靠数据驱动视图改变的一种框架,它的核心驱动方法就是用其提供的 setState 方法设置 state 中的数据从而驱动存放在内存中的虚拟 DOM 树的更新 更新方法就是通过 React 的 Diff 算法比较旧虚拟 DOM 树和新虚拟 DOM 树之间的 Chan…

单例设计模式(3)

单例模式(3) 实现集群环境下的分布式单例类 如何理解单例模式中的唯一性? 单例模式创建的对象是进程唯一的。以springboot应用程序为例,他是一个进程,可能包含多个线程,单例代表在这个进程的某个类是唯一…

ROS 2边学边练(6)-- 何为参数(parameters)

概念 这一知识点,应该很好理解,参数就是节点的属性,比如猫科动物,它所拥有的属性(参数)有胡子、能伸缩的爪子、随光线缩放自如的瞳孔、夜视能力、优秀的弹跳力、萌等等。ROS节点中参数支持的数据类型有整型…

Springboot中的三层架构

我们在进行前后端交互的时候,会分为数据访问,业务逻辑,接受请求并响应数据三个操作,这三部分其实是可以拆分的,让他们解耦,否则代码复用性差并且不易维护,所以诞生了三层架构——1.Dao(数据访问…

VuePress基于 Vite 和 Vue 构建优秀框架

VitePress 是一个静态站点生成器 (SSG),专为构建快速、以内容为中心的站点而设计。简而言之,VitePress 获取用 Markdown 编写的内容,对其应用主题,并生成可以轻松部署到任何地方的静态 HTML 页面。 VitePress 附带一个用于技术文档…

Redis 常见数据结构及命令

目录 一.Redis常见的数据结构 二.Redis数据结构对应的命令 1.String类型 2.Hash类型 3.List类型 4.Set类型 5.Sorted Set类型 一.Redis常见的数据结构 Redis支持多种数据结构,包括字符串(string)、哈希(hash)、…

【Linux】认识线程池 AND 手撕线程池(正常版)

文章目录 0.回顾进程池1.计算机层面的池化技术2.线程池预备知识2.1介绍线程池2.2设计线程池的意义是什么?2.3其他知识 3.回顾C类与对象3.1cpp什么情况下成员函数必须是静态的?3.1可变参数列表3.2格式化输出函数3.3预定义符号 4.图解线程池运作原理4.0完整…