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

【设计模式】单例模式Singleton(Java)

文章目录

  • 定义
  • 类图
  • Java经典实现
    • 懒汉Lazy Mode:
    • 饿汉Eager Mode:
  • 在饿汉下的多线程案例
  • 在懒汉下的多线程案例
  • 总结

定义

单例模式(单件模式)确保一个类只有一个实例,并提供一个全局访问点。——HeadFirst

单例模式通过过防止外部实例化和修改来控制创建的对象的数量。

关键点:

  • 私有构造函数,没有其他类可以实例化一个新对象。
  • 私有引用-没有外部修改。
  • Public static getInstance方法是唯一可以获取对象的地方。

问:为什么单例模式能确保实例独一无二?
答:因为单例模式没有公开的构造器,构造器是私有的,因此他人无法自己创建实例对象。而且他人想获取实例必须通过调用getInstance静态方法得到实例,实例也许是调用时创建的,也许是之前已经创建好的。

类图

在这里插入图片描述

Java经典实现

私有构造器、一个静态方法、一个静态变量。

懒汉Lazy Mode:

public class Singleton{// 使用一个静态变量记录Stingleton的唯一实例private static Singleton uniqueInstance;// 这里是其他有用的实例化变量// 私有构造方法private Singleton(){} public static Singleton getInstance(){if(uniqueInstance == null){uniqueInstance = new Singleton();}return uniqueInstance;}// 其他有用的方法
}

饿汉Eager Mode:

public class Singleton2 {// 使用一个静态私有变量记录Stingleton的唯一实例private static Singleton2 uniqueInstance = new Singleton2();// 这里是其他有用的实例化变量// 私有构造方法private Singleton2(){}public static Singleton2 getInstance(){return uniqueInstance;}// 其他有用的方法
}

在饿汉下的多线程案例

单例类GlobalNum.java

public class GlobalNum {private static  GlobalNum gn=new GlobalNum();private int num=0;public static GlobalNum getInstance(){return gn;}public synchronized int getNum() //加锁{return ++num; //返回访问次数}
}

主方法SingleMain.java

class NumThread extends Thread{private String threadName;public NumThread(String name){threadName=name;}public void run(){ GlobalNum gnObj=GlobalNum.getInstance();for (int i = 0; i < 5; i++) {System.out.println(threadName+"第"+gnObj.getNum()+"次访问");try {this.sleep(1000);} catch (Exception e) {// TODO: handle exceptionSystem.out.println("错误");} }}
}public class SingleMain {
//测试单件模式public static void main(String[] args) {// TODO Auto-generated method stubNumThread thread1=new NumThread("线程1");NumThread thread2=new NumThread("线程2");thread1.start();thread2.start();}
}

JDK8运行结果:

线程12次访问
线程21次访问
线程13次访问
线程24次访问
线程15次访问
线程26次访问
线程17次访问
线程28次访问
线程19次访问
线程210次访问

在懒汉下的多线程案例

getInstance方法添加synchronized关键字,防止不同线程创建多个实例对象从而违反单例模式。

public class GlobalNum {private static GlobalNum globalNum;private int num=0;// getInstance方法添加synchronized关键字,防止创建多个实例public static synchronized GlobalNum getInstance(){if(globalNum==null){globalNum = new GlobalNum();return globalNum;}return globalNum;}public synchronized int getNum() //加锁{return ++num; //返回访问次数}
}

主方法SingleMain.java

同上

输出结果:

线程11次访问
线程22次访问
线程14次访问
线程23次访问
线程16次访问
线程25次访问
线程17次访问
线程28次访问
线程19次访问
线程210次访问

如果上述getInstance不添加synchronized,则会造成输出:

线程11次访问
线程21次访问
线程12次访问
线程22次访问
线程13次访问
线程23次访问
线程14次访问
线程24次访问
线程15次访问
线程25次访问

—————————————
上述懒汉下的多线程案例虽然达到预想效果但是存在缺陷:为了防止多个线程创建多个对象,给getInstance添加synchronized,但实际上只有第一次执行getInstance方法,才需要真正的同步,当已经创建好对象时,后续无需在同步getInstance方法(导致后续每次调用getInstance,同步变成累赘,性能资源浪费)。

改进:使用双重检查加锁,减少使用同步。

添加volatile及synchronized同步块

public class GlobalNum {private static volatile GlobalNum globalNum;private int num=0;public static  GlobalNum getInstance(){if(globalNum==null){synchronized(GlobalNum.class){if(globalNum==null)globalNum = new GlobalNum();}}return globalNum;}public synchronized int getNum() //加锁{return ++num; //返回访问次数}
}

总结

  • 单例模式确保一个程序中的一个类只有一个实例。
  • 单例模式提供访问这个实例的全局访问点。
  • Java实现单例模式:私有构造器、一个静态变量、一个静态方法。
  • 确定性能资源的限制后,在多线程情况下,谨慎选择合适的方法实现单例模式。

参考:
HeadFirst设计模式、https://www.programcreek.com/2011/07/java-design-pattern-singleton/

相关文章:

【设计模式】单例模式Singleton(Java)

文章目录定义类图Java经典实现懒汉Lazy Mode&#xff1a;饿汉Eager Mode&#xff1a;在饿汉下的多线程案例在懒汉下的多线程案例总结定义 单例模式&#xff08;单件模式&#xff09;确保一个类只有一个实例&#xff0c;并提供一个全局访问点。——HeadFirst 单例模式通过过防…...

机器学习中的公平性

文章目录机器学习公平性评估指标群体公平性指标个人公平性指标引起机器学习模型不公平的潜在因素提升机器学习模型公平性的措施机器学习公平性 定义&#xff1a; 机器学习公平性主要研究如何通过解决或缓解“不公平”来增加模型的公平性&#xff0c;以及如何确保模型的输出结果…...

Docker镜像之Docker Compose讲解

文章目录1 docker-compose1.1 compose编排工具简介1.2 安装docker-compose1.3 编排启动镜像1.4 haproxy代理后端docker容器1.5 安装socat 直接操作socket控制haproxy1.6 compose中yml 配置指令参考1.6.1 简单命令1.6.2 build1.6.3 depends_on1.6.4 deploy1.6.5 logging1.6.6 ne…...

蓝桥杯30天真题冲刺|题解报告|第三十天

大家好&#xff0c;我是snippet&#xff0c;今天是我们这次蓝桥省赛前一起刷题的最后一天了&#xff0c;今天打了一场力扣周赛&#xff0c;前面3个题都是有思路的&#xff0c;第三个题只过了一半的案例&#xff0c;后面看完大佬们的题解彻悟&#xff0c;下面是我今天的题解 目录…...

配置 Git Husky 代码提交约束

介绍 Git Husky 是一个可以管理 Git Hooks 的工具&#xff0c;它可以帮助我们在代码提交的时候运行脚本&#xff0c;以确保代码提交符合特定的规范和约定。 在 Git 中&#xff0c;允许在操作特定的事件时执行特定的脚本&#xff0c;这些事件我们称之为 Hooks。 Git Husky 利…...

IntelliJ IDEA 2023.1 最新变化

文章目录IntelliJ IDEA 2023.1 最新变化一. 主要更新1. 新 UI 增强 测试版启用新 UI2. 在项目打开时更早提供 IDE 功能3. 更快地导入 Maven 项目4.后台提交检查5. Spring Security 匹配器和请求映射的导航 Ultimate二. 用户体验1. 全 IDE 缩放2. 保存多个工具窗口布局的选项3. …...

stm32学习笔记-9 USART串口

9 USART串口 文章目录9 USART串口9.1 串口通信协议9.2 stm32的片上外设-USART9.3 USART收发相关实验9.3.1 实验1&#xff1a;串口发送9.3.2 实验2&#xff1a;移植printf函数9.3.3 实验3&#xff1a;串口发送接收9.4 USART串口数据包9.5 USART数据包相关实验9.5.1 实验1&#x…...

【蓝桥杯】每日四道编程题(两道真题+两道模拟)| 第四天

专栏&#xff1a; 蓝桥杯——每日四道编程题&#xff08;两道真题两道模拟&#xff09; “蓝桥杯就要开始了&#xff0c;这些题刷到就是赚到” ₍ᐢ..ᐢ₎♡ 另一个专栏&#xff1a; 蓝桥杯——每日四道填空题&#xff08;两道真题两道模拟题&#xff09; 目录 专栏&#xff1…...

大家有没有时候觉得,递归,分治,回溯,傻傻分不清楚?

递归&#xff0c;分治&#xff0c;回溯的定义 递归&#xff08;Recursion&#xff09; 递归是一种解决问题的方法&#xff0c;它将一个问题分解成一个或多个较小的相同类型的子问题&#xff0c;然后通过递归调用自身来解决这些子问题。递归通常包括一个基本情况&#xff08;b…...

Java 8 - Lambda 表达式

1. 函数式接口 当一个接口中只有一个非 default 修饰的方法&#xff0c;这个接口就是一个函数式接口用 FunctionalInterface 标注 1&#xff09;只有一个抽象方法 FunctionalInterface public interface MyInterface {void print(int x); } 2&#xff09;只有一个抽象方法和…...

【Ruby学习笔记】4.Ruby 类和对象及类案例

前言 本章介绍Ruby的类和对象及类案例。 Ruby 类和对象 Ruby 是一种完美的面向对象编程语言。面向对象编程语言的特性包括&#xff1a; 数据封装数据抽象多态性继承 这些特性将在 面向对象的 Ruby 中进行讨论。 一个面向对象的程序&#xff0c;涉及到的类和对象。类是个别…...

分享一个计算表格内单元格合并的工具,支持行合并、列合并等常见场景

分享一个计算表格内单元格合并的工具&#xff0c;支持行合并、列合并等常见场景 效果图 安装 cj-toolkit-x/table-cell-merger 插件 npm i cj-toolkit-x/table-cell-merger使用方法 import {TableCellMerger} from "cj-toolkit-x/table-cell-merger" // 创建一个单…...

CUDA编程(三):Hello world

CUDA编程&#xff08;三&#xff09;&#xff1a;Hello worldCUDA编程Hello worldCUDA编程 CUDA是Compute Unified Device Architecture的缩写&#xff0c;由英伟达公司2007年开始推出&#xff0c;初衷是为GPU增加一个易用的编程接口&#xff0c;让开发者无需学习复杂的着色语…...

二十九、String的不可变性

一、String的基本特性 1.String:字符串&#xff0c;使用一对“”引起来表示 1)String s1 “hallo”; //字面量的定义方式 2)String 说 new String(“hello”)’ 2.String声明为final的&#xff0c;不可被继承。 3.String实现了Serialzable接口:表示字符串是支持序列化的。实…...

TCP服务器如何使用select处理多客户连接

TCP是一种面向连接的通信方式,一个TCP服务器难免会遇到同时处理多个用户的连接请求的问题,本文用一个简化的实例说明如何在一个TCP服务器程序中,使用select处理同时出现的多个客户连接,文章给出了程序源代码,本文假定读者已经具备了基本的socket编程知识,熟悉基本的服务器…...

python字符编码

目录 ❤ 前言 文本编辑器存取文件的原理&#xff08;nodepad&#xff0c;pycharm&#xff0c;word&#xff09; python解释器执行py文件的原理 &#xff0c;例如python test.py 总结 ❤ 什么是字符编码? ASCII MBCS Unicode ❤ 字符编码的发展史 阶段一: 现代计算…...

面向对象练习题(8)

目录 第一题 第二题 第三题 第一题 思路分析&#xff1a; 1.Person p new Student();这就是一个向上转型&#xff0c;让父类的引用指向子类的对象&#xff0c;但是向上转型不能访问子类的属性和方法 我们在写代码时看的是编译类型 在运行是看的是运行类型 p.run(); p.eat(); …...

重构类关系-Extract Interface提炼接口八

重构类关系-Extract Interface提炼接口八 1.提炼接口 1.1.使用场景 若干客户使用类接口中的同一子集&#xff0c;或者两个类的接口有部分相同。将相同的子集提炼到一个独立接口中。 类之间彼此互用的方式有若干种。“使用一个类”通常意味用到该类的所有责任区。另一种情况…...

vivo手机各系列简介和拆解

Vivo是中国智能手机制造商&#xff0c;其产品线较多&#xff0c;主要包括以下系列&#xff1a; X系列&#xff1a;X系列是Vivo的高端智能手机系列&#xff0c;注重出色的拍照性能、高质量的音效和高端的设计。该系列主要面向追求高质量拍照和高端体验的用户。 V系列&#xff1…...

Redis:redis通用命令;redis常见数据结构;redis客户端;redis的序列化

一、redis命令 1.redis通用命令 Redis 通用命令是一些 Redis 下可以作用在常用数据结构上的常用命令和一些基础的命令 常见的命令有&#xff1a; keys 查看符合模板的所有key&#xff0c;不建议在生产环境设备上使用&#xff0c;因为keys会模式匹配所有符合条件的key&#…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...