设计模式之单例模式详解

单例模式

描述:单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。

核心特点

  1. 单例类只有一个实例对象
  2. 该单例对象必须由单例类自行创建
  3. 单例类对外提供一个访问该单例的全局访问点

实现方式

​ 通常,普通类的构造函数是公有的,外部类可以通过“new 构造函数()”来生成多个实例。但是,如果将类的构造函数设为私有的,外部类就无法调用该构造函数,也就无法生成多个实例。这时该类自身必须定义一个静态私有实例,并向外提供一个静态的公有函数用于创建或获取该静态私有实例。

角色功能

  • 单例类:包含一个实例且能自行创建这个实例的类。
  • 访问类:使用单例的类。

类图:
请添加图片描述

优点:

  • 单例模式可以保证内存里只有一个实例,避免重复创建和销毁,减少了内存的开销
  • 可以避免对资源的多重占用。
  • 单例模式设置全局访问点,可以优化和共享资源的访问。

缺点:

  • 单例模式一般没有接口,扩展困难。如果要扩展,则除了修改原来的代码,没有第二种途径,违背开闭原则。
  • 在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模拟生成一个新的对象。
  • 单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。

实现代码

实现要点:private修饰默认构造函数、private static修饰实例对象、public static修饰获取实例的方法

懒汉式单例

该模式的特点是类加载时没有生成单例,只有当第一次调用 getlnstance 方法时才去创建这个单例,第一次用到才创建实例,所以叫懒汉(这其实是优点)。

特点:

  • 实现简单
  • 首次使用时才创建对象实例(实现了懒加载)
  • 若想实现线程安全则必须使用synchronized,效率较低
public class LazySingleton {private static volatile LazySingleton instance = null;    //保证 instance 在所有线程中同步private LazySingleton() {}    //private 避免类在外部被实例化public static synchronized LazySingleton getInstance() {//getInstance 方法前加同步if (instance == null) {instance = new LazySingleton();}return instance;}
}

双重校验机制

属于懒汉式的拓展实现

特点:

  • 能实现懒加载,也是线程安全的,且效率较高
  • 实现复杂,需要两次校验(进入同步块后还要校验一次)
public class Singleton {  private volatile static Singleton singleton;  private Singleton (){}  public static Singleton getSingleton() {  if (singleton == null) {  synchronized (Singleton.class) {  if (singleton == null) {  singleton = new Singleton();  }  }  }  return singleton;  }  
}

问:为什么synchronized语句不把第一个if判断语句要包括进去?

答:包括进去就和synchronized方法没区别了,效率很低。

问:为什么synchronized语句块创建实例对象前还要再判断一次实例是否被创建?

答:为了保证实例只被创建一次。如果初始实例为null时,有多个线程进入到第一个判断语句并竞争锁,拿到锁的线程如果已经创建了实例后,后续拿到锁的线程就不能再创建了,所以要再判断一次。换句话说synchronized去修饰实例创建语句时候,只能保证同时刻只有一个在创建,而不能保证后续没有别的线程去创建。

饿汉式单例

该模式的特点是类一旦加载就创建一个单例,保证在调用 getInstance 方法之前单例已经存在了,它是线程安全的,可以直接用于多线程而不会出现问题。

特点:

  • 类加载时就创建好对象实例,也就是不管是否用到都初始化,浪费内存
  • 天然的线程安全,不需要使用到锁
public class HungrySingleton {//类加载时就会创建实例化对象private static HungrySingleton instance = new HungrySingleton();private HungrySingleton() {}public static HungrySingleton getInstance() {return instance;}
}

静态内部类

属于饿汉式的拓展,解决饿汉式无法实现懒加载问题,能实现和双重校验机制一样的效果。

在单例类里面创建一个SingletonHolder内部静态类,外部的单例类被加载时不会立马初始化内部静态类,只有去调用内部静态类的静态成员或静态方法才会触发类的加载,也能够实现第一次用到时才加载,也就是懒加载。

public class Singleton {  //内部静态类,单例类加载时不会立马初始化,只有访问内部静态变量时才初始化private static class SingletonHolder {  private static Singleton INSTANCE = new Singleton();  }  //空的构造方法private Singleton (){}  public static Singleton getInstance() {  return SingletonHolder.INSTANCE;  }  
}

枚举式

单例模式的最佳方法,非常简洁、高效、线程安全、支持序列化机制、无法被反射机制破解(其它方式都可以)。

    public enum Singleton {INSTANCE;  // 枚举里的属性相当于Singleton的实例private Person instance;Singleton() {// 私有构造函数 默认是 privateinstance = new Person(); // 在构造函数中完成实例化操作}public static Person getInstance() {// 提供公有方法对其访问return instance;}}// 在外部使用Singleton.INSTANCE.getInstance();来调用
}

如何选?

  • 懒汉式要么线程不安全,要么效率低,要么实现复杂,不建议使用。
  • 如果单例对象占用资源大,需要懒加载,建议用内部静态类方式(优于懒汉式)。
  • 如果单例对象占用资源小,不需要懒加载,建议用枚举式(优于饿汉式)。

应用场景

对于 Java来说,单例模式可以保证在一个 JVM 中只存在单一实例。单例模式的应用场景主要有以下几个方面。

  • 某类需要频繁创建销毁,且资源消耗又比较大的对象,如线程池数据库连接池、配置文件、日志管理等,单例可提高性能和节省资源。
  • 当对象需要多线程共享访问的场合。由于单例模式只允许创建一个对象,能够保证线程安全性且达到共享目的。
  • 外部和内部资源管理。对于管理外部打印机、回收站内部属性文件的系统,单例模式可以确保这些资源被系统中的唯一实例所管理。
  • 对于一些控制硬件级别的操作,或者从系统上来讲应当是单一控制逻辑的操作,如果有多个实例,则系统会完全乱套。

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

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

相关文章

OpenCV 入门(一) —— OpenCV 基础

OpenCV 入门系列: OpenCV 入门(一)—— OpenCV 基础 OpenCV 入门(二)—— 车牌定位 OpenCV 入门(三)—— 车牌筛选 OpenCV 入门(四)—— 车牌号识别 OpenCV 入门&#xf…

每日两题 / 23. 合并 K 个升序链表 94. 二叉树的中序遍历(LeetCode热题100)

23. 合并 K 个升序链表 - 力扣(LeetCode) 若lists有k个元素,调用k - 1次(两个有序链表的合并)即可 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNod…

探索鸿蒙开发:鸿蒙系统如何引领嵌入式技术革新

嵌入式技术已经成为现代社会不可或缺的一部分。而在这个领域,华为凭借其自主研发的鸿蒙操作系统,正悄然引领着一场技术革新的浪潮。本文将探讨鸿蒙开发的特点、优势以及其对嵌入式技术发展的深远影响。 鸿蒙操作系统的特点 鸿蒙,作为华为推…

一键接入电商API数据接口淘宝API通过商品ID、URL采集商品详情页实时数据API接入指南

一键接入电商API数据接口,尤其是淘宝API,通常需要遵循以下步骤: 注册账号:注册接入账号获取Api Key和Api Secret。 选择API:根据需要选择合适的API服务,如通过商品ID或URL采集商品详情页数据的API。 权限…

WPF鼠标拖拽的最佳实现

WPF鼠标拖拽的最佳实现 在很多项目中都会遇到鼠标拖拽控件移动的需求,常见的有从在列表中拖拽列表项移动,拖拽控件移动等。 本文将介绍2种拖拽的简单的实现 列表项的拖拽 本文将使用 gong-wpf-dragdrop 这个github上的库来实现列表的拖拽的效果&…

GitLab使用记录

GitLab 文章目录 1. 常用命令1.1 配置邮箱 用户名1.2 查看配置1.3 基本语法 2. 连接gitlab3. 直接拉去项目 1. 常用命令 1.1 配置邮箱 用户名 git config --global user.name ShangzheChen git config --global user.email 735511377qq.com1.2 查看配置 cat ~/.gitconfig这…

企业信使_登陆页

在当今数字化时代,企业与员工之间的沟通变得越来越重要。为了满足企业内部沟通的需求,一款功能强大而方便使用的企业信使_登陆页应运而生。企业信使_登陆页是一种专为企业内部使用而设计的通讯工具,可以帮助企业提高沟通效率,加强…

4.用python爬取保存在text中的格式为m3u8的视频

文章目录 一、爬取过程详解1.寻找视频的m3u8链接2.从网页源码中寻找视频的m3u8链接的第二部分内容3.从视频的m3u8链接获取视频 二、完整的代码 一、爬取过程详解 1.寻找视频的m3u8链接 这个文档承接了爬虫专栏的 第一节.python爬虫爬取视频网站的视频可下载的源url&#xff0…

车规级低功耗汽车用晶振SG-9101CGA

车规级晶振SG-9101CGA属于爱普生9101系列,是一款可编程晶振。SG-9101CGA车规级晶振采用2.5x2.0mm封装,利用PLL技术生产,此款振荡器的频率范围从0.67M~170MHZ任一频点可选,步进1ppm,采用标准CMOS输出,最大输…

为 Flutter 应用设置主题:ThemeData 和 ColorScheme 指南

在媒体和其他来源中有许多关于这个主题的文章,那么这篇文章的必要性是什么? 在本文中,我计划仅关注 ThemeData 小部件的关键点以及我的开发经验中最常用的参数,并且您将获得有关每个参数如何对您的应用程序执行操作的简要说明。 …

分类任务的基础学习

1.什么是分类? 2.局限性: 当样本量逐渐变大的时候,准确率会下降——>因为线性回归曲线距离我们的原点越远,预测就会开始不准确,因为 x前面的倍数就会越来越小,这就导致了样本量变大,但是那些…

Kafka 业务日志采集最佳实践

简介 Apache Kafka 是一个分布式流处理平台,主要用于构建实时数据流管道和应用程序。在收集业务日志的场景中,Kafka 可以作为一个消息中间件,用于接收、存储和转发大量的日志数据。将 Kafka 与其他系统(如 Elasticsearch、Flume、…

docker-compose安装 人大金仓数据库

下载官网安装包 将安装包重命名为: kingbase.tar 再导入镜像仓库 docker load -i kingbase.tar目录创建data文件夹创建docker-compose文件 version: 3 services: kingbase: image: kingbase:v1 container_name: kingbaseports: - "54321:54321" volumes: -…

解决微信小程序电脑能正常使用,手机端无法正常访问的SSL证书问题

目录 前言1 问题描述与调试2 探索问题根源2.1 用户反馈收集2.2 尝试手机端访问2.3 PC端调试 3 确认问题与解决方案3.1 检查SSL证书3.2 重新部署SSL证书3.3 测试修复效果 4 SSL(Secure Sockets Layer)证书中间证书4.1 SSL证书链的构成4.2 中间证书的作用 …

【管理咨询宝藏97】智慧物流园区顶层设计方案

本报告首发于公号“管理咨询宝藏”,如需阅读完整版报告内容,请查阅公号“管理咨询宝藏”。 【管理咨询宝藏97】智慧物流园区顶层设计方案 【格式】PDF版本 【关键词】智慧园区、制造型企业转型、数字化转型 【核心观点】 - 中国物流业整体呈现集中度低…

springboot项目 字典/枚举翻译 终极解决方案 AOP+自定义注解+递归实体字段+实体动态三级缓存+责任链+多种转换方式

目录 前言实现思路技术确定 食用方式效果使用样例项目中使用第一步 复制包第二步 实现LoadDictDatabase并将其注入容器第三步 标识需要翻译的字段第四步 标识需要翻译的方法第五步 调用需要翻译的方法 实现细节TODO 前言 字典,即在存储介质中进行存储时,为了避免业务上对其名称…

数据结构复习指导之二叉树的概念

文章目录 二叉树 考纲内容 复习提示 1.二叉树的概念 1.1二叉树的定义及其主要特性 1.1.1二叉树的定义 1.1.2几种特殊的二叉树 1.1.3二叉树的性质 1.2二叉树的存储结构 1.2.1顺序存储结构 1.2.2链式存储结构 知识回顾 二叉树 考纲内容 (一)树…

苹果Mac用户下载VS Code(Universal、Intel Chip、Apple Silicon)哪个版本?

苹果macOS用户既可以下载通用版(Universal),软件将自动检测用户的处理器并进行适配。 也可以根据型号下载对应CPU的版本: 使用Intel CPU的Mac电脑可下载Intel Chip版本; 使用苹果自研M系列CPU的Mac电脑下载Apple Si…

Context capture/Pix4Dmapper/AutoCAD/CASS/EPS软件的安装流程与使用方法;土方量计算;无人机摄影测量数据处理

目录 专题一 无人机摄影测量技术应用现状及其发展 专题二 基本原理和关键技术讲解 专题三 无人机影像外业数据获取 专题四 数据处理环境建立与软件熟悉 专题五 GNSS数据土方量计算 专题六 基于无人机影像数据的正射影像制作 专题七 基于无人机影像数据的三维模型制作 专…

gocator导出图片

想用3D扫描后的图片,但是系统自带的导出方法很麻烦,所以考虑通过sdk导出 首先需要设置点云亮度 这里是导出图片的关键代码 case GoDataMessageType.SurfaceIntensity: { Debug.WriteLine("SurfaceIntensity "); GoSu…