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

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 接口,在进行反序列化时可能会破坏单例模式。
  • 对象创建时机不可控:由于是在类加载时创建实例,因此无法控制实例创建的时机。

总结:

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

相关文章:

Java 中的单例模式

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

鸿蒙OS开发实例:【ArkTS类库多线程I/O密集型任务开发】

使用异步并发可以解决单次I/O任务阻塞的问题,但是如果遇到I/O密集型任务,同样会阻塞线程中其它任务的执行,这时需要使用多线程并发能力来进行解决。 I/O密集型任务的性能重点通常不在于CPU的处理能力,而在于I/O操作的速度和效率。…...

OpenStack部署

目录 一、安装环境 1.无网络使用该命令 2.修改主机名 3.配置hosts解析 4.配置本机免密 5.关闭防火墙和SElinux策略 6.关闭NewworkManager 7.修改yum源 7.1下载阿里源 7.2清空并加载缓存yum源 8.安装基本工具 9.系统升级 10.安装OPenStack的yum仓库 11.修改OPenSt…...

Java中的多线程和线程安全问题

线程 线程是操作系统进行调度的最小单位。一个进程至少包含一个主线程,而一个线程可以启动多个子线程。线程之间共享进程的资源,但也有自己的局部变量。多线程程序和普通程序的区别:每个线程都是一个独立的执行流;多个线程之间是…...

java Web会议信息管理系统 用eclipse定制开发mysql数据库BS模式java编程jdbc

一、源码特点 jsp 会议信息管理系统是一套完善的web设计系统,对理解JSP java SERLVET mvc编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,eclipse开发,数据库为Mysql5.0&am…...

lock4j学习记录

一种简单的,支持不同方案的高性能分布式锁 简介 lock4j是一个分布式锁组件,其提供了多种不同的支持以满足不同性能和环境的需求。 立志打造一个简单但富有内涵的分布式锁组件。 特性 简单易用,功能强大,扩展性强。支持redis…...

【C++庖丁解牛】自平衡二叉搜索树--AVL树

🍁你好,我是 RO-BERRY 📗 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油 目录 前言1 AVL树的概念2. AVL…...

ES5和ES6的深拷贝问题

深拷贝我们知道是引用值的一个问题,因为在拷贝的时候,拷贝的是在内存中同一个引用。所以当其中的一个应用值发生改变的时候,其他的同一个引用值也会发生变化。那么针对于这种情况,我们需要进行深度拷贝,这样就可以做到…...

阿里云发送短信配置

依赖 <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.2.1</version> </dependency> <dependency><groupId>org.apache.httpcomponents</groupId&g…...

axios封装,请求取消和重试,请求头公共参数传递

axios本身功能已经很强大了&#xff0c;封装也无需过度&#xff0c;只要能满足自己项目的需求即可。 常规axios封装&#xff0c;只需要设置&#xff1a; 实现请求拦截实现响应拦截常见错误信息处理请求头设置 import axios from axios;// 创建axios实例 const service axios…...

隐私计算实训营学习五:隐语PSI介绍及开发指南

文章目录 一、SPU 实现的PSI介绍1.1 PSI定义和种类1.1.1 PSI定义和种类1.1.2 隐语PSI功能分层 1.2 SPU 实现的PSI介绍1.2.1 半诚实模型1.2.2 PSI实现位置 二、SPU PSI调度架构三、Secretflow PSI开发指南四、隐语PSI后续计划 一、SPU 实现的PSI介绍 1.1 PSI定义和种类 1.1.1 …...

ES的RestClient相关操作

ES的RestClient相关操作 Elasticsearch使用Java操作。 本文仅介绍CURD索引库和文档&#xff01;&#xff01;&#xff01; Elasticsearch基础&#xff1a;https://blog.csdn.net/weixin_46533577/article/details/137207222 Elasticsearch Clients官网&#xff1a;https://ww…...

linux通用命令 ssh命令连接慢问题排查

系列文章目录 文章目录 系列文章目录一、 ssh 连接慢3.1 查找原因3.2 解决方案 一、 ssh 连接慢 最近的 koji 服务器 使用 ssh 连接很慢。 3.1 查找原因 可以通过 ssh -vvv 192.168.0.123 或 time ssh root192.168.0.123 exit 查找原因如下&#xff1a; SERVER的SSHD会去DN…...

7.卷积神经网络与计算机视觉

计算机视觉是一门研究如何使计算机识别图片的学科&#xff0c;也是深度学习的主要应用领域之一。 在众多深度模型中&#xff0c;卷积神经网络“独领风骚”&#xff0c;已经被称为计算机视觉的主要研究根据之一。 一、卷积神经网络的基本思想 卷积神经网络最初由 Yann LeCun&a…...

Linux|如何管理多个Git身份

摘要 关于如何管理不同项目和多个Git身份。 作为一名通用软件开发者&#xff0c;我经常发现自己在处理各种各样的项目&#xff0c;每个项目都有自己的要求和期望。这包括为个人、工作和客户项目管理不同的Git身份。以下是我组织Git仓库以简化这一过程的方法。 目录组织 我将我的…...

力扣---最长回文子串---二维动态规划

二维动态规划思路&#xff1a; 首先&#xff0c;刚做完这道题&#xff1a;力扣---最长有效括号---动态规划&#xff0c;栈-CSDN博客&#xff0c;所以会有一种冲动&#xff0c;设立g[i]&#xff0c;表示以第i位为结尾的最长回文子串长度&#xff0c;然后再遍历一遍取最大长度即可…...

(一)kafka实战——kafka源码编译启动

前言 本节内容是关于kafka消息中间键的源码编译&#xff0c;并通过idea工具实现kafka服务器的启动&#xff0c;使用的kafka源码版本是3.6.1&#xff0c;由于kafka源码是通过gradle编译的&#xff0c;以及服务器是通过scala语言实现&#xff0c;我们要预先安装好gradle编译工具…...

Spring Boot 使用 Redis

1&#xff0c;Spring 是如何集成Redis的&#xff1f; 首先我们要使用jar包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><gro…...

火车头通过关键词采集文章的原理

随着互联网信息的爆炸式增长&#xff0c;网站管理员和内容创作者需要不断更新和发布新的文章&#xff0c;以吸引更多的用户和提升网站的排名。而火车头作为一款智能文章采集工具&#xff0c;在这一过程中发挥着重要作用。本文将探讨火车头如何通过关键词采集文章&#xff0c;以…...

Kafka 面试题及参考答案

目录 1. Kafka 的核心特性是什么? 2. Kafka 为什么能够实现高吞吐量? 3. Kafka 的消息丢失是...

内存分配函数malloc kmalloc vmalloc

内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

Unity中的transform.up

2025年6月8日&#xff0c;周日下午 在Unity中&#xff0c;transform.up是Transform组件的一个属性&#xff0c;表示游戏对象在世界空间中的“上”方向&#xff08;Y轴正方向&#xff09;&#xff0c;且会随对象旋转动态变化。以下是关键点解析&#xff1a; 基本定义 transfor…...

【Veristand】Veristand环境安装教程-Linux RT / Windows

首先声明&#xff0c;此教程是针对Simulink编译模型并导入Veristand中编写的&#xff0c;同时需要注意的是老用户编译可能用的是Veristand Model Framework&#xff0c;那个是历史版本&#xff0c;且NI不会再维护&#xff0c;新版本编译支持为VeriStand Model Generation Suppo…...

负载均衡器》》LVS、Nginx、HAproxy 区别

虚拟主机 先4&#xff0c;后7...