设计模式之单例模式
时间:2022-06-05
本文章向大家介绍设计模式之单例模式,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
应用场景
- Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗? 不信你自己试试看哦~
- windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
- 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。
在Spring管理的Bean中,默认就是单例存在的,让我们来深入了解单例模式
举栗子,在小说神雕侠侣中只会有一个小龙女不然那就成西游记,一根毫毛一个分身
饿汉模式
package com.tanoak.create.single;
/**
* @author tanoak@qq.com
* @date 2018/7/18 15:29
* @Desc 小龙女 单例 =>饿汉模式 不会存在多线程并发问题 但是占用内存
*/
public class DragonGirl1 {
private String name ;
private String sex ;
private String desc ;
private DragonGirl1(){}
private static DragonGirl1 girl = new DragonGirl1();
public static DragonGirl1 getInstance() {
return girl;
}
}
懒汉模式
/**
* @author tanoak@qq.com
* @date 2018/7/18 15:29
* @Desc 小龙女 单例 =>懒汉模式
*/
public class DragonGirl2 {
private String name ;
private String sex ;
private String desc ;
private DragonGirl2(){}
private static DragonGirl2 girl = null;
public static DragonGirl2 getInstance(){
if (null == girl) {
girl = new DragonGirl2();
}
return girl;
}
}
会存在并发问题,因为调用newInstance()方法时没有加锁,导致会并发执行,如图:
双重检查机制
/**
* @author tanoak@qq.com
* @date 2018/7/18 15:29
* @Desc 小龙女 单例 =>双重检查机制
*/
public class DragonGirl3 {
private String name ;
private String sex ;
private String desc ;
private DragonGirl3(){}
private static volatile DragonGirl3 girl = null;
public static DragonGirl3 getInstance(){
if (null == girl) {
synchronized (DragonGirl3.class){
if(null ==girl){
girl = new DragonGirl3(); //1
}
}
}
return girl;
}
}
这种方式是最常用的,我也比较喜欢用这种方式,在这里注意volatile这个关键字,
作用:禁止指令重排序(不对volatile做详细介绍),详细了解volatile可以参考这篇博文volatile详解。
为什么要禁止指令重排序?
这是因为在jdk1.5之后,JAVA是无序写入,可能会造成顺序的颠倒,即内存分配、返回对象引用、初始化的顺序,这种情况下对应到//1就是singleton已经不是null,而是指向了堆上的一个对象,但是该对象却还没有完成初始化动作。当后续的线程发现singleton不是null而直接使用的时候,就会出现问题。
测试
/**
* @author tanoak@qq.com
* @date 2018/7/18 15:29
* @Desc 单例模式
*/
public class Main {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 50; i++) {
createThread();
}
}
private static void createThread() throws Exception{
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+" :=> "+DragonGirl1.getInstance());
// System.out.println(Thread.currentThread().getName()+" :=> "+DragonGirl2.getInstance());
// System.out.println(Thread.currentThread().getName()+" :=> "+DragonGirl3.getInstance());
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
在Java中还可以用枚举类型来实现单例,但是日常的开发中使用的比较少,主要还是习惯原因,想了解的可以参考枚举单例这篇博文
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【每日一题】30. Substring with Concatenation of All Words
- MySQL选错索引导致的线上慢查询事故复盘
- 【Kubernetes】additionalPrinterColumns的配置
- ES使用json字符串索引文档时报错
- VUE 过滤输入框中的特殊字符 只保存中文、英文及数字
- Java 判断一个字符串是不是由数字组成
- 解决ES搜索过程中使用高亮插件导致结果不完整的问题
- Java selenuim用执行js模拟鼠标滚动的方式
- 使用puppeteer 进行批量网页截图
- dubbo 配置优先级 集群模式 负载均衡策略
- 【STM32F407开发板用户手册】第33章 STM32F407的SPI总线应用之驱动DAC8563
- Salesforce LWC学习(二十) CLI篇:新版本不支持Audience解决方案
- 【STM32F429开发板用户手册】第33章 STM32F429的SPI总线应用之驱动DAC8563
- ELK学习笔记之filbeat pod无法将容器日志发送
- 小学生看了都会的Apache配置虚拟主机教程