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

Java面试之单例模式的六种实现方式

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、为什么要用单例模式
  • 二、单例模式的六种实现
    • 2.1 饿汉式
      • 2.1.1 饿汉式代码实现
      • 2.1.2 饿汉式代码实现要点解析
      • 2.1.3 饿汉式代码实现优点
      • 2.1.4 饿汉式代码实现缺点
    • 2.2 懒汉式1.0
      • 2.2.1 懒汉式1.0代码实现
      • 2.2.2 懒汉式1.0代码实现要点解析
      • 2.2.3 懒汉式1.0代码实现优点
      • 2.2.4 懒汉式1.0代码实现缺点
    • 2.3 懒汉式2.0
      • 2.3.1 懒汉式2.0代码实现
      • 2.3.2 懒汉式2.0代码实现要点解析
      • 2.3.3 懒汉式2.0代码实现优点
      • 2.3.4 懒汉式2.0代码实现缺点
    • 2.4 懒汉式3.0——双重检查Double Check
      • 2.4.1 双重检查代码实现
      • 2.4.2 双重检查代码实现要点解析
      • 2.4.3 双重检查代码实现优点
      • 2.4.4 双重检查代码实现缺点
    • 2.5 静态内部类(推荐)
      • 2.5.1 静态内部类代码实现
      • 2.5.2 静态内部类代码实现要点解析
      • 2.5.3 静态内部类代码实现优点
      • 2.5.4 静态内部类代码实现缺点
      • 2.5.5 静态内部类与饿汉式对比
    • 2.6 枚举(推荐)
      • 2.6.1 枚举代码实现
      • 2.6.2 枚举代码实现要点解析
      • 2.6.3 枚举实现优点


前言

由于设计模式在面向对象中起着举足轻重的作用,在面试中很多公司都喜欢问一下有关设计模式的问题。在常用的设计模式中,Singleton单例模式是唯一一个能用短短几十行代码完整实现的模式,因此,写一个Singletion类型是一个很常见的面试题。


一、为什么要用单例模式

节省内存,单例对象可避免频繁的创建与销毁,带来性能的提升。
在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。

二、单例模式的六种实现

2.1 饿汉式

2.1.1 饿汉式代码实现

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

2.1.2 饿汉式代码实现要点解析

1、私有构造
2、创建私有静态实例
3、提供公有静态get方法返回该静态实例

2.1.3 饿汉式代码实现优点

1、实现简单
2、无线程安全问题

2.1.4 饿汉式代码实现缺点

1、初始化耗时,导致系统启动缓慢
2、在类装载的时候就完成了实例化,没有做到Lazy Loading(延迟加载)、按需加载
3、极端情况下,还是可以拿到多实例,如通过反射。

2.2 懒汉式1.0

2.2.1 懒汉式1.0代码实现

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

2.2.2 懒汉式1.0代码实现要点解析

1、私有构造
2、初始化一个为null的静态实例instance
3、提供公有静态get方法,判断instance为null时,则创建该对象并赋给instance,然后返回该静态实例

2.2.3 懒汉式1.0代码实现优点

1、延迟加载,在使用时才会开辟空间

2.2.4 懒汉式1.0代码实现缺点

1、线程不安全,只能在单线程情况下使用,在多线程情况下,一个线程进if(instance == null)判断中,还未来得及创建对象,另外一个线程也来到判断语句,这时也会通过判断,这样就会创建多个实例。

总的来说在多线程环境中不能使用这种方式。

2.3 懒汉式2.0

2.3.1 懒汉式2.0代码实现

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

2.3.2 懒汉式2.0代码实现要点解析

1、私有构造
2、创建私有静态实例
3、提供加synchronized的公有静态get方法返回该静态实例

2.3.3 懒汉式2.0代码实现优点

1、用的时候开辟内存
2、解决线程安全问题

2.3.4 懒汉式2.0代码实现缺点

1、效率太低。下一个线程想要获取对象,必须等待上一个线程释放锁之后才能获取。每次调用都需要获取锁与释放锁,在大量并发请求时将产生性能问题。
2、并发度低。由于加入了synchronized,并行度为1,导致并发度低。
3、极端情况下,还是可以拿到多实例,如通过反射。

2.4 懒汉式3.0——双重检查Double Check

2.4.1 双重检查代码实现

public class Singleton{private Singleton(){}private static Singleton instance = null;public static synchronized Singleton getInstance(){if(instance == null){//这个检查是提高效率的synchronized (Singleton.class){if(instance == null){//这个检查是保证线程安全的instance = new Singleton();}}}return instance;}
}

2.4.2 双重检查代码实现要点解析

1、私有构造
2、创建私有静态实例
3、提供加synchronized的公有静态get方法返回该静态实例,该get方法中首先判断instance是否为null,然后加个synchronized块,里面再对instance进行判断,为空才创建对象

2.4.3 双重检查代码实现优点

1、实现简单
2、立即加载,无线程安全问题

2.4.4 双重检查代码实现缺点

极端情况下,还是可以拿到多实例,如通过反射。

2.5 静态内部类(推荐)

2.5.1 静态内部类代码实现

public class Singleton{private Singleton(){}private static Singleton SingletonInstance {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance(){return SingletonInstance.INSTANCE;}
}

2.5.2 静态内部类代码实现要点解析

1、私有构造
2、创建私有静态内部类,该静态内部类中含有static 和final修饰的实例对象
3、提供公有静态get方法返回该静态实例

2.5.3 静态内部类代码实现优点

1、延迟加载,效率高
2、无线程安全问题。类的静态属性只会在第一次加载类时初始化,这样JVM帮助我们保证了线程安全性,因为在类初始化时别的线程无法进入。

2.5.4 静态内部类代码实现缺点

静态内部类虽然保证了单例在多线程并发下的线程安全性,但是在遇到序列化对象时,默认的方式运行得到的结果就是多例的。
极端情况下,还是可以拿到多实例,如通过反射。

2.5.5 静态内部类与饿汉式对比

此方法可以看作饿汉式的改进版,两者都采用类装载机制来保证初始化实例时只有一个线程。
不同之处在于饿汉式只要Singleton类被装载就会实例化,没有延迟加载;
而静态内部类方式再Singleton类被装载时并不会立即实例化,而是在需要实例化时才会调用getInstance方法装载SingletonInstance 类,从而完成Singleton实例化。

总的来说推荐使用。

2.6 枚举(推荐)

2.6.1 枚举代码实现

public class Singleton{//内部类使用枚举类private enum SingletonEnum {INSTANCE;private Singleton singleton;//在枚举类的构造器里初始化singletonSingletonEnum() {singleton = new Singleton ();}private Singleton getSingleton() {return singleton;}}//对外提供获取单例的方法public static Singleton getInstance(){return SingletonEnum.INSTANCE.getSingleton();}
}

2.6.2 枚举代码实现要点解析

1、内部类使用枚举类
2、在枚举类的构造器里初始化singleton,提供私有方法供本类获取singleton
3、对外提供获取单例的方法

2.6.3 枚举实现优点

1、支持延迟加载,可做到按需加载
2、支持高并发
3、防止反射和反序列化攻击

总的来说推荐使用。


相关文章:

Java面试之单例模式的六种实现方式

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、为什么要用单例模式二、单例模式的六种实现2.1 饿汉式2.1.1 饿汉式代码实现2.1.2 饿汉式代码实现要点解析2.1.3 饿汉式代码实现优点2.1.4 饿汉式代码实现缺…...

re正则入门

🌸re正则入门 正则表达式 (Regular Expression) 又称 RegEx, 是用来匹配字符的一种工具. 在一大串字符中寻找你需要的内容. 它常被用在很多方面, 比如网页爬虫, 文稿整理, 数据筛选等等 简单的匹配 正则表达式无非就是在做这么一回事. 在文字中找到特定的内容, 比如…...

C++ Day5

目录 一、静态成员 1.1 概念 1.2 格式 1.3 银行账户实例 二、类的继承 2.1 目的 2.2 概念 2.3 格式 2.4 继承方式 2.5 继承中的特殊成员函数 2.5.1 构造函数 2.5.2析构函数 2.5.3 拷贝构造函数 2.5.4拷贝赋值函数 总结: 三、多继承 3.1 概念 3.2 格…...

el-element:自定义参数

希望在下拉框、输入框、多选框中添加自定义参数,这在项目中是非常常见的 1、 Select选择器中remote-method方法带自定义参数 :remote-method"(query)>{remoteMethod(query,自定义参数)}" remoteMethod(query, pid){ } 2、 el多选框方法追加参数&…...

“分布式”与“集群”初学者的技术总结

一、“分布式”与“集群”的解释: 分布式:把一个囊肿的系统分成无数个单独可运行的功能模块 集群: 把相同的项目复制进行多次部署(可以是一台服务器多次部署,例如使用8080部署一个,8081部署一个&#xff0c…...

C++day5(静态成员、类的继承、多继承)

一、Xmind整理&#xff1a; 二、上课笔记整理&#xff1a; 1.静态数据成员静态成员函数&#xff08;银行账户实例&#xff09; #include <iostream>using namespace std;class BankAccount { private:double balance; //余额static double interest_rate; //利率 p…...

2023MySQL+MyBatis知识点整理

文章目录 主键 外键 的区别&#xff1f;什么是范式&#xff1f;什么是反范式&#xff1f;什么是事务&#xff1f;MySQL事务隔离级别&#xff1f;MySQL事务默认提交模式&#xff1f;MySQL中int(1)和int(10)的区别MySQL 浮点数会丢失精度吗&#xff1f;MySQL支持哪几种时间类型&a…...

【随笔】如何使用阿里云的OSS保存基础的服务器环境

使用阿里云OSS创建一个存储仓库&#xff1a;bucket 在Linux上下载并安装阿里云的ossutil工具 // 命令行&#xff0c;是linux环境 3. 安装ossutil。sudo -v ; curl https://gosspublic.alicdn.com/ossutil/install.sh | sudo bash 说明:安装过程中&#xff0c;需要使用解压工具…...

汽车电子笔记之:AUTOSA架构下的多核OS操作系统

目录 1、AUTOSAR多核操作系统 1.1、OS Application 1.2、多核OS的软件分区 1.3、任务调度 1.4、核间任务同步 1.5、计数器、报警器、调度表 1.6、自旋锁与共享资源 1.7、核间通信IOC 1.8、OS Object中元素交互 1.9、多核OS的启动与关闭 2、多核OS注意事项 2.1、最小…...

解决华为云ping不通的问题

进入华为云控制台。依次选择&#xff1a;云服务器->点击服务器id->安全组->更改安全组->添加入方向规则&#xff0c;添加一个安全组规则&#xff08;ICMP&#xff09;&#xff0c;详见下图 再次ping公网ip就可以ping通了 产生这一问题的原因是ping的协议基于ICMP协…...

数据结构入门 — 链表详解_双向链表

前言 数据结构入门 — 双向链表详解* 博客主页链接&#xff1a;https://blog.csdn.net/m0_74014525 关注博主&#xff0c;后期持续更新系列文章 文章末尾有源码 *****感谢观看&#xff0c;希望对你有所帮助***** 系列文章 第一篇&#xff1a;数据结构入门 — 链表详解_单链表…...

时序预测 | MATLAB实现PSO-KELM粒子群算法优化核极限学习机时间序列预测(含KELM、ELM等对比)

时序预测 | MATLAB实现PSO-KELM粒子群算法优化核极限学习机时间序列预测&#xff08;含KELM、ELM等对比&#xff09; 目录 时序预测 | MATLAB实现PSO-KELM粒子群算法优化核极限学习机时间序列预测&#xff08;含KELM、ELM等对比&#xff09;预测效果基本介绍模型介绍程序设计参…...

SSL/TLS协议的概念、工作原理、作用以及注意事项

个人主页&#xff1a;insist--个人主页​​​​​​ 本文专栏&#xff1a;网络基础——带你走进网络世界 本专栏会持续更新网络基础知识&#xff0c;希望大家多多支持&#xff0c;让我们一起探索这个神奇而广阔的网络世界。 目录 一、SSL/TLS协议的基本概念 二、SSL/TLS的工作…...

[Stable Diffusion教程] 第一课 原理解析+配置需求+应用安装+基本步骤

第一课 原理解析配置需求应用安装基本步骤 本次内容记录来源于B站的一个视频 以下是自己安装过程中整理的问题及解决方法&#xff1a; 问题&#xff1a;stable-diffusion-webui启动No Python at ‘C:\xxx\xxx\python.exe‘ 解答&#xff1a;打开webui.bat 把 if not de…...

uniapp结合Canvas+renderjs根据经纬度绘制轨迹(二)

uniapp结合Canvasrenderjs根据经纬度绘制轨迹 文章目录 uniapp结合Canvasrenderjs根据经纬度绘制轨迹效果图templaterenderjsjs数据结构 ​ 根据官方建议要想在 app-vue 流畅使用 Canvas 动画&#xff0c;需要使用 renderjs 技术&#xff0c;把操作canvas的js逻辑放到视图层运…...

VR全景加盟会遇到哪些问题?全景平台会提供什么?

想创业&#xff0c;你是否也遇到这些问题呢&#xff1f;我是外行怎么办&#xff1f;没有团队怎么办&#xff1f;项目回本周期快吗&#xff1f;项目靠谱吗&#xff1f;加盟平台可信吗&#xff1f;等等这类疑问。近几年&#xff0c;VR产业发展迅速&#xff0c;尤其是VR全景项目在…...

如何进行微服务的集成测试

集成测试的概念 说到集成测试&#xff0c;相信每个测试工程师并不陌生&#xff0c;它不是一个崭新的概念&#xff0c;通过维基百科定义可以知道它在传统软件测试中的含义。 Integration testing (sometimes called integration and testing, abbreviated I&T) is the pha…...

spark grpc 在master运行报错 exitcode13 User did not initialize spark context

程序使用sparksql 以及protobuf grpc &#xff0c;执行报错 ApplicationMaster: Final app status: FAILED, exitCode: 13, (reason: Uncaught exception: java.lang.IllegalStateException: User did not initialize spark context! 先说原因 &#xff1a; 1.使用了不具备权限…...

nginx 反向代理的原理

Nginx&#xff08;发音为"engine X"&#xff09;是一个高性能、轻量级的开源Web服务器和反向代理服务器。它的反向代理功能允许将客户端的请求转发到后端服务器&#xff0c;然后将后端服务器的响应返回给客户端。下面是Nginx反向代理的工作原理&#xff1a; 1.客户端…...

【SpringBoot】第二篇:RocketMq使用

背景&#xff1a; 本文会介绍多种案例&#xff0c;教大家如何使用rocketmq。 一般rocketmq使用在微服务项目中&#xff0c;属于分模块使用。这里使用springboot单体项目来模拟使用。 本文以windows系统来做案例。 下载rocketmq和启动&#xff1a; RocketMQ 在 windows 上运行…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent

安全大模型训练计划&#xff1a;基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标&#xff1a;为安全大模型创建高质量、去偏、符合伦理的训练数据集&#xff0c;涵盖安全相关任务&#xff08;如有害内容检测、隐私保护、道德推理等&#xff09;。 1.1 数据收集 描…...

抽象类和接口(全)

一、抽象类 1.概念&#xff1a;如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象&#xff0c;这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法&#xff0c;包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中&#xff0c;⼀个类如果被 abs…...