【设计模式-2.1】创建型——单例模式

说明:设计模式根据用途分为创建型、结构性和行为型。创建型模式主要用于描述如何创建对象,本文介绍创建型中的单例模式。

饿汉式单例

单例模式是比较常见的一种设计模式,旨在确保对象的唯一性,什么时候去使用这个对象都是同一个。这样设计的目的是为了避免对象重复创建,浪费资源,同时也保证了对象的唯一性,不至于多个相同的对象,状态不一致的情况。

以下是单例模式的简单实现:

/*** 太阳类*/
public class Sun {private static final Sun sun = new Sun();private Sun() {}public static Sun getInstance() {return sun;}
}

需要注意,对象的创建是在对象类内部,且为static final修饰,并且私有化构造方法,使其不能在外部被创建,其次创建一个静态方法,返回其对象

此时,外部通过类名.方法名的方式,可以访问到该对象,且始终为同一个;

public class Test {public static void main(String[] args) {Sun sun1 = Sun.getInstance();Sun sun2 = Sun.getInstance();System.out.println(sun1 == sun2);}
}

两次获取到的对象相同

在这里插入图片描述

上面这种创建方式,称为饿汉式单例(Eager Singleton),即类加载完成时就创建对象

懒汉式单例

以下这种方式,称为懒汉式单例(Lazy Singleton),在调用静态方法时才创建对象

/*** 懒汉式单例模式*/
public class LazySun {private static LazySun sun = null;private LazySun() {}public static LazySun getInstance() {if (sun == null) {sun = new LazySun();}return sun;}
}

这种创建方式,可以实现延迟加载,节约资源。但是在多线程并发时,如果有多个线程在if (sun == null),就会导致对象被创建多次,所以我们很容易想到的是加锁,将静态方法加上锁,如下:

/*** 懒汉式单例模式*/
public class LazySun {private static LazySun sun = null;private LazySun() {}public synchronized static LazySun getInstance() {if (sun == null) {sun = new LazySun();}return sun;}
}

但是,给方法加上锁后,会影响性能,可以考虑减少锁的范围,只锁住创建对象这一行,如下:

/*** 懒汉式单例模式*/
public class LazySun {private static LazySun sun = null;private LazySun() {}public static LazySun getInstance() {if (sun == null) {synchronized (LazySun.class) {sun = new LazySun();}}return sun;}
}

双重检查锁定

但是,还有问题。在多线程并发下,如果线程A在创建对象(未完成),线程B、C在if (sun == null) 这里判断为true,即便对象创建完成,线程B、C通过了if判断,也还是会依次再创建对象,也造成了对象被重复创建。因此,还需要改造,如下:

/*** 双重检查锁定*/
public class LazySun {private volatile static LazySun sun = null;private LazySun() {}public static LazySun getInstance() {// 第一次判断if (sun == null) {synchronized (LazySun.class) {// 第二次判断if (sun == null){sun = new LazySun();}}}return sun;}
}

就是在锁住的代码块里面再进行一次非空判断,称为双重检查锁定(Double-Check Locking),同时,单例对象修饰符加上volatile,确保多个线程都能正确处理;

IoDH

饿汉式单例,是在类被加载时就创建了对象。不需要考虑多线程,但是无论是否使用到对象都创建,造成了资源浪费。而懒汉式单例,虽然做到了延迟加载,但是需要处理好多线程情况下的对象创建,使用了锁,影响了性能。

那有没有一种更好了方式,既能在多线程下使用,又不会影响性能?

在《设计模式的艺术》(刘伟著)中作者提供了一种更好的创建方式,称为IoDH(Initialization on Demand Holder,按需初始化),代码如下:

/*** IoDH*/
public class Singleton {private Singleton() {}private static class HolderClass {private final static Singleton instance = new Singleton();}public static Singleton getInstance() {return HolderClass.instance;}
}

这种方式是对饿汉式单例的改进,是在单例类里创建了一个内部类,将单例对象的创建放在了这个内部类里面。因为单例对象不是单例类的一个成员变量,所以对象在类加载时不会被创建,而是会在调用静态方法时被创建,这样既能延迟加载,又没有使用锁,影响性能,一举两得。

书中说,通过使用IoDH,既可以实现延迟加载,又可以保证线程安全,不影响系统性能。因此,IoDH不失为一种最好的Java语言单例模式实现方式;其缺点是与编程语言本身的特性相关,很多面向对象语言不支持IoDH。

总结

本文参考《设计模式的艺术》、《秒懂设计模式》两书

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

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

相关文章

MySQL 批量插入记录报 Error 1390 (HY000)

文章目录 1.背景2.问题3.分批插入4.一次最多能插入多少条记录?参考文献 1.背景 Golang 后台服务使用 GORM 实现与 MySQL 的交互,在实现一个通过 Excel 导入数据的接口时,使用 Save 方法一次性插入大量记录(>1w)时报…

LiveGBS流媒体平台GB/T28181功能-查看国标设备会话列表直播会话、回放会话、下载会话、对讲会话

LiveGBS流媒体平台GB/T28181功能-查看国标设备会话列表直播会话、回放会话、下载会话、对讲会话 1、会话列表2、会话类型3、搭建GB28181视频直播平台 1、会话列表 LiveGBS-> 国标设备-》点击在线状态 点击会话列表 2、会话类型 下拉会话类型可以看到 直播会话、回放会话、…

不用排队升级GPT/获取api

想要在国内获取api key,可以使用这种方法 小技巧:目前GPT还是排队订阅,可以直接用链接:https://chat.openai.com/invite/accepted 即可跳过排队环节 接下来先看一下如何购买腾讯云服务器 第一步:打开腾讯云 腾讯云 …

Visual Studio 2019 C# System.BadImageFormatException 解决方法

文章目录 1.DLL文件缺失或不匹配原因解决方法 2.系统环境变量Path下内容过多原因解决方法 3.位数错误原因解决方法 分析几种可能因素 1.DLL文件缺失或不匹配 原因 检查对应Debug路径下的DLL文件是否有缺失 解决方法 将对应的DLL文件放到Debug文件夹里面,检查冗余…

抖音权重查询源码H5源码

源码下载:123网盘

2022年12月 Scratch(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 默认小猫角色和气球角色都是显示状态,小猫程序如下图所示,气球没有程序,点击绿旗,舞台上最终显示的效果是?( ) A:可能出现6个不同位置的小猫和6个小球 B:可能出现6个不同位…

python 爬百度热搜并生成词云

1、爬取百度body存入txt def get_baidu_hot():url "https://top.baidu.com/board?tabrealtime"headers {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3&…

Python 前后端分离项目Vue部署应用

一、视图创建 from django.http import JsonResponse from django.shortcuts import render# Create your views here. from django.views import Viewclass IndexView(View):def get(self,request):# 前后端分离 (前端JS代码渲染数据)return JsonRespo…

Jensen不等式

如果是正数,并且它们的和等于1,f是凸函数,那么: 也可表述为: 即x期望的凸函数值小于等于x凸函数值的期望

可验证随机函数(VRF)

文章目录 一、背景以及场景共识发展第一代 POW “以力取胜”第二代 POS/DPOS “民主投票”第三代 VRF “运气抽签” 二、可验证随机函数(VRF)快速开始1. VRF是什么?2. MD5 hash函数和VRF(Verifiable Random Function)区别3. VRF-…

【刷题宝典NO.4】

目录 公交站间的距离 生命游戏 公交站间的距离 https://leetcode.cn/problems/distance-between-bus-stops/ 环形公交路线上有 n 个站,按次序从 0 到 n - 1 进行编号。我们已知每一对相邻公交站之间的距离,distance[i] 表示编号为 i 的车站和编号为 …

程序员职场可能遇到的问题总结!

在职场中,你是否遇到过这样的领导或同事,他可能是自恋狂,自吹自擂自我标榜;可能是团队合作的绊脚石,对团队合作态度消极并频繁拖后腿;可能是抱怨专家,满满负能量;可能是完美主义者&a…

二十一、数组(6)

本章概要 数组排序Arrays.sort的使用并行排序binarySearch二分查找parallelPrefix并行前缀 数组排序 根据对象的实际类型执行比较排序。一种方法是为不同的类型编写对应的排序方法,但是这样的代码不能复用。 编程设计的一个主要目标是“将易变的元素与稳定的元素…

win11渗透武器库,囊括所有渗透工具

开箱即用,最全的武器库,且都是2023年11月最新版,后续自己还可以再添加,下载地址:https://download.csdn.net/download/weixin_59679023/88565739 服务连接 信息收集工具 端口扫描 代理抓包 漏洞扫描 指纹识别 webshel…

移动机器人路径规划(七)--- 基于MDP的路径规划MDP-Based Planning

目录 1 什么是MDP-Based Planning 2 worst-case analysis for nondeterministic model 3 Expected Cost Planning 4 Real Time Dynamic Programming(RTDP) 1 什么是MDP-Based Planning 之前我们从起点到终点存在很多可执行路径,我们可以…

Python实现一箭穿心

文章目录 🎄效果🏳️‍🌈Turtle模块🌹代码🌺代码讲解 🎄效果 🏳️‍🌈Turtle模块 Turtle是一个绘图工具,是Python标准库中的一个模块。它提供了一种简单而直观的方式来创…

【C++】内存管理(new与delete)

👀樊梓慕:个人主页 🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》 🌝每一个不曾起舞的日子,都是对生命的辜负 前言 本篇文章我们一起来学习C的内存管理方式&…

最新yolov8环境搭建、推理训练一站式超详细教学

1、获取yolov8源码 访问yolov8_github官网,网络不稳定时可能需要加速器。yolov8源码地址 获取方式:直接下载或者git工具克隆 我使用git操作进行演示,复制github上的地址(需提前关闭加速器)。 git clone https://github.com/ultralytics/ul…

UI自动化(selenium+python)之元素定位的三种等待方式!

前言 在UI自动化过程中,常遇到元素未找到,代码报错的情况。这种情况下,需要用等待wait。 在selenium中可以用到三种等待方式即sleep,implicitly_wait,WebDriverWait 一、固定等待(sleep) 导入time模块,设定固定的等待时间 缺…

计数问题+约瑟夫问题(map)

目录 一、计数问题 二、约瑟夫问题 一、计数问题 #include<iostream> #include<map> using namespace std; int main() {int n,x;cin>>n>>x;map<int,int>m;for(int i1;i<n;i){if(i>1 && i<10){m[i];}else{int temp i;while (…