设计模式之单例

文章目录

  • 前言
  • 一、单例模式的基本定义
  • 二、懒汉式单例
  • 三、饿汉式单例
  • 四、懒汉式单例存在的线程安全问题
  • 总结


前言

单例模式是比较经典的设计模式,本篇我们将结合实际案例说明单例模式的实现原理,以及存在的问题。


一、单例模式的基本定义

单例模式(Singleton Pattern)确保某一个类只有一个实例方法,而且自行实例化并向整个系统提供这个实例,这个类被称为单例类,它提供全局访问方法。单例模式的要点有三个:

  • 某个类只能有一个实例
  • 它必须自行创建这个实例
  • 它必须自行向整个系统提供这个实例

二、懒汉式单例

代码实现如下:

public class LazyWaterCup {// 定义一个静态引用private static LazyWaterCup wc;// 构造方法私有private LazyWaterCup(){}// 提供一个全局访问点public static LazyWaterCup getInstance() {if (wc == null){wc = new LazyWaterCup();}return wc;}
}

首先我们要声明一个类引用,其次构造方法必须是私有的,以保证外部对于此类无法直接通过new进行类的实例化,与此同时我们要提供一个对外的方法,在此方法中实现类的实例化,也需要进行一个判断,若类引用没有指向任何对象,就创建一个对象,让引用指向它。

测试结果如下:

public class Test {public static void main(String[] args) {LazyWaterCup lwc1 = LazyWaterCup.getInstance();LazyWaterCup lwc2 = LazyWaterCup.getInstance();LazyWaterCup lwc3 = LazyWaterCup.getInstance();System.out.println("lwc1= " + lwc1);System.out.println("lwc2= " + lwc2);System.out.println("lwc3= " + lwc3);}
}

在这里插入图片描述
如图三次调用都指向同一个对象,因为从第一个getInstance()被调用时,由于类引用指向->null所以会创建对象,后续再调用getInstance()方法就不会再创建对象而是将上一个对象地址返回。因此三次打印结果都是指向同一个对象。

三、饿汉式单例

代码如下:

public class HungryWaterCup {// 定义一个静态引用private final static HungryWaterCup wc = new HungryWaterCup();// 构造方法私有private HungryWaterCup(){}// 提供一个全局访问点public static HungryWaterCup getInstance() {return wc;}
}

饿汉式单例与懒汉式单例的区别在于它对于对象的创建比较急迫,在声明的时候就创建一个对象,使声明的引用指向它,它是在类的装载过程中就完成的。

测试结果如下:

public class Test {public static void main(String[] args) {HungryWaterCup hwc1 = HungryWaterCup.getInstance();HungryWaterCup hwc2 = HungryWaterCup.getInstance();HungryWaterCup hwc3 = HungryWaterCup.getInstance();System.out.println("hwc1= " + hwc1);System.out.println("hwc2= " + hwc2);System.out.println("hwc3= " + hwc3);}
}

在这里插入图片描述

四、懒汉式单例存在的线程安全问题

懒汉式单例是在getInstance()被调用的时候创建的,若此时有大量线程访问此方法,就会创建多个对象,我们可以测试一下:
在这里插入图片描述
在创建对象的时候先让线程睡眠1ms,方便模拟多线程环境。

public class Test {public static void main(String[] args) {for (int i = 0; i < 200; i++) {Thread t1 = new Thread(() -> {try {LazyWaterCup lwc = LazyWaterCup.getInstance();System.out.println("lwc->" + lwc);} catch (InterruptedException e) {throw new RuntimeException(e);}}, "t1");t1.start();}}
}

在测试类代码中,创建200个线程。运行结果如下图:
在这里插入图片描述
创建的对象很多不一样。解决线程安全问题,一般可以在可能出现并发安全的代码块加上对象锁,就是synchronized锁,我们上锁之后,再试试:
在这里插入图片描述
测试结果:
在这里插入图片描述
就可以保证创建的对象是同一个。


总结

今天对单例模式的分析就到这里了,后续会继续总结其他设计模式的原理与实现。

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

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

相关文章

STM32定义变量到指定内存位置

rt thread&#xff0c; 怎么定义变量到指定内存位置&#xff1f; OpenCat是由未来可编程机器人宠物制造商Petoi开发的基于Arduino和Raspberry Pi的开源四足机器人宠物框架。 非 gcc 版 定义一个宏 #ifndef __MEMORY_AT #if (defined (__CC_ARM)) #define _…

Vue--》打造个性化医疗服务的医院预约系统(一)

今天开始使用 vue3 ts 搭建一个医院预约系统的前台页面&#xff0c;因为文章会将项目的每一个地方代码的书写都会讲解到&#xff0c;所以本项目会分成好几篇文章进行讲解&#xff0c;我会在最后一篇文章中会将项目代码开源到我的GithHub上&#xff0c;大家可以自行去进行下载运…

Win11 设置FTP服务详细教程

起因&#xff1a; 因测试需要&#xff0c;本机建立FTP服务测试使用&#xff0c;此文章用于记录使用&#xff01; 操作步骤&#xff1a; 1、配置FTP功能 ①、"winR" > 在运行窗口输入"control" 回车&#xff1b; ②、打开"控制面板" > 点击…

【专题速递】传输网络优化(长专题)

// RTC如何助力远程医疗&#xff1f;5G的差异化体现在哪&#xff1f;SMT如何将远程做到极致&#xff1f;7月29日LiveVideoStackCon2023上海站传输网络优化专场&#xff0c;为您解答。 传输网络优化 为应对互联网日益增长的加速需求、复杂的网络环境以及多种多样的视频业务&am…

Linux常见命令

这里写目录标题 Linux 背景知识Linux环境搭建方式使用终端软件连接到 LinuxLinux 常用命令特殊的目录:绝对路径 与 相对路径vim Linux 背景知识 Linux 是一个操作系统. 和 Windows 是 “并列” 的关系. 安卓系统本质上就是 Linux. 一个完整的操作系统 操作系统内核 配套的…

ylb-接口7注册发送短信

总览&#xff1a; 在common模块下引入短信验证码的依赖项&#xff08;生成4位随机数&#xff09;&#xff1a; 在web模块下的resources/application.yml&#xff0c;添加配置信息&#xff08;京东万象&#xff09;&#xff1a; #短信配置 jdwx:sms:url: https://way.jd.com…

ORB-SLAM2学习笔记2之TUM开源数据运行ORB-SLAM2生成轨迹并用evo工具评估轨迹

文章目录 0 引言1 evo工具1.1 简介1.2 常用命令1.3 安装 2 TUM数据3 单目ORB-SLAM23.1 运行ORB-SLAM23.2 evo评估轨迹3.2.1 载入和对比轨迹3.2.2 计算绝对位姿误差 4 RGB-D ORB-SLAM24.1 运行ORB-SLAM24.2 evo评估轨迹4.2.1 载入和对比轨迹4.2.2 计算绝对轨迹误差 ORB-SLAM2学习…

2003-Can‘t connect to Mysql server on ‘xxx‘ (10060 “Unknown error“)

Navicat连接 阿里云 服务器MySQL5.7数据库报错 解决办法&#xff1a; 进入数据库执行以下sql 1.允许root用户远程连接 GRANT ALL PRIVILEGES ON *.* TO root% IDENTIFIED BY 数据库密码 WITH GRANT OPTION; 2.刷新权限 FLUSH PRIVILEGES;3.执行quit退出数据库 quit; 4.…

uniapp连接到微信小程序

第一次使用uniapp连接到微信小程序&#xff0c;但是出现了define is not defined问题&#xff0c;让人头疼&#xff0c;出现这个问题的原因是 调试基础库 版本过高导致的&#xff01; 解决办法&#xff1a; 点击设置&#xff0c;选择项目设置。&#xff0c;会进入到如下界面&a…

mac M1 安装nacos

背景 m1不支持本地安装&#xff0c;只能用docker &#xff1a; “由于 rocksdb 暂不支持 M1 平台&#xff0c;所以使用 Zulu JDK 的小伙伴们运行 Nacos 2.x 版本会报错&#xff0c;网上通用的解决方案是使用 Oracle JDK 来运行 Nacos 2.x 版本&#xff0c;但对于强迫症的我来说…

Windows VScode如何配置与使用git?

当我们在VScode中编写代码后&#xff0c;需要提交到git仓库时&#xff0c;但是我们又不想切换到git的命令行窗口&#xff0c;我们可以在VScode中配置git&#xff0c;然后就可以很方便快捷的把代码提交到仓库中。 1. 官网下载安装Git命令行工具 根据自己的电脑系统&#xff0c…

选择正确的负载均衡器:LVS还是Nginx?

选择正确的负载均衡器&#xff1a;LVS还是Nginx&#xff1f; 博主简介一、前言二、什么是LVS&#xff1f;2.1、LVS的架构 三、什么是Nginx&#xff1f;3.1、Nginx 特性3.2、Nginx 架构 四、LVS和Nginx的区别五、总结 博主简介 &#x1f4a1;一个热爱分享高性能服务器后台开发知…