设计模式之单列模式(7种单例模式案例,Effective Java 作者推荐枚举单例模式)

news/2024/11/14 5:25:00/

前言
设计模式中按照不同的处理方式共包含三大类;创建型模式、结构型模式和行为模式,其中创建型模式目前已经介绍了其中的四个;工厂方法模式、抽象工厂模式、生成器模式和原型模式,除此之外还有最后一个单例模式

单列模式介绍
在这里插入图片描述
单例模式可以说是整个设计中最简单的模式之一,而且这种方式即使在没有看设计模式相关资料也会常用在编码开发中。
案例场景
1:数据库的连接池不会反复创建
2:spring中一个单例模式bean的生成和使用
3:在我们平常的代码中需要设置全局的的一些属性保存

7种单例模式实现
静态类使用

java">package com.lm.design;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;public class Singleton_00 {public static Map<String,String> cache = new ConcurrentHashMap<String, String>();}

以上这种方式在我们平常的业务开发中非常常见,这样静态类的方式可以在第一次运行的时候直接初始化Map类,同时这里我们也不需要到延迟加载再使用。
在不需要维持任何状态下,仅仅用于全局访问,这个使用静态类的方式更加方便。
但如果需要被继承以及需要维持一些特定状态的情况下,就适合使用单例模式

懒汉模式(线程不安全)

java">package com.lm.design;public class Singleton_01 {private static Singleton_01 instance;private Singleton_01() {}public static Singleton_01 getInstance() {if (null != instance) {return instance;}return new Singleton_01();}}

单例模式有一个特点就是不允许外部直接创建,也就是new Singleton_01(),因此这里在默认的构造函数上添加了私有属性 private。
目前此种方式的单例确实满足了懒加载,但是如果有多个访问者同时去获取对象实例你可以想象成一堆人在抢厕所,就会造成多个同样的实例并存,从而没有达到单例的要求。
懒汉模式(线程安全)

java">package com.lm.design;public class Singleton_02 {private static Singleton_02 instance;private Singleton_02() {}public static synchronized Singleton_02 getInstance() {if (null != instance) {return instance;}return new Singleton_02();}}

饿汉模式(线程安全)

java">package com.lm.design;public class Singleton_03 {private static Singleton_03 instance = new Singleton_03();private Singleton_03() {}public static Singleton_03 getInstance() {return instance;}}

此种方式与我们开头的第一个实例化Map基本一致,在程序启动的时候直接运行加载,后续有外部需要使用的时候获取即可。
但此种方式并不是懒加载,也就是说无论你程序中是否用到这样的类都会在程序启动之初进行创建。
使用类的内部类(线程安全)

java">package com.lm.design;public class Singleton_04 {private static class SingletonHolder {private static Singleton_04 instance = new Singleton_04();}private Singleton_04() {}public static Singleton_04 getInstance() {return SingletonHolder.instance;}}

双重锁校验(线程安全)

java">package com.lm.design;public class Singleton_05 {private static volatile Singleton_05 instance;private Singleton_05() {}public static Singleton_05 getInstance(){if(null != instance){return instance;}synchronized (Singleton_05.class){if (null == instance){instance = new Singleton_05();}}return instance;}}

双重锁的方式是方法级锁的优化,减少了部分获取实例的耗时。
同时这种方式也满足了懒加载。
CAS「AtomicReference」(线程安全)

java">package com.lm.design;import java.util.concurrent.atomic.AtomicReference;public class Singleton_06 {private static final AtomicReference<Singleton_06> INSTANCE = new AtomicReference<Singleton_06>();private static Singleton_06 instance;private Singleton_06() {}public static final Singleton_06 getInstance() {for (; ; ) {Singleton_06 instance = INSTANCE.get();if (null != instance) return instance;INSTANCE.compareAndSet(null, new Singleton_06());return INSTANCE.get();}}public static void main(String[] args) {System.out.println(Singleton_06.getInstance()); // org.itstack.demo.design.Singleton_06@2b193f2dSystem.out.println(Singleton_06.getInstance()); // org.itstack.demo.design.Singleton_06@2b193f2d}}

A:java并发库提供了很多原子类来支持并发访问的数据安全性;AtomicInteger、AtomicBoolean、AtomicLong、AtomicReference。
AtomicReference 可以封装引用一个V实例,支持并发访问如上的单例方式就是使用了这样的一个特点。
B:使用CAS的好处就是不需要使用传统的加锁方式保证线程安全,而是依赖于CAS的忙等算法,依赖于底层硬件的实现,来保证线程安全。相对于其他锁的实现没有线程的切换和阻塞也就没有了额外的开销,并且可以支持较大的并发性。
C:当然CAS也有一个缺点就是忙等,如果一直没有获取到将会处于死循环中。
Effective Java作者推荐的枚举单例(线程安全)

java">package com.lm.design;public enum Singleton_07 {INSTANCE;public void test(){System.out.println("hi~");}}

Effective Java 作者推荐使用枚举的方式解决单例模式,此种方式可能是平时最少用到的。
这种方式解决了最主要的;线程安全、自由串行化、单一实例。
总结
1:虽然只是一个很平常的单例模式,但在各种的实现上真的可以看到java的基本功的体现,这里包括了;懒汉、饿汉、线程是否安全、静态类、内部类、加锁、串行化等等。
2:在平时的开发中如果可以确保此类是全局可用不需要做懒加载,那么直接创建并给外部调用即可。但如果是很多的类,有些需要在用户触发一定的条件后(游戏关卡)才显示,那么一定要用懒加载。线程的安全上可以按需选择。

好了 至此 设计模式之单列模式(7种单例模式案例,Effective Java 作者推荐枚举单例模式) 学习结束了 友友们 点点关注不迷路 老铁们!!!!!


http://www.ppmy.cn/news/1546573.html

相关文章

SystemVerilog学习笔记(六):控制流

条件语句 条件语句用于检查块中的语句是否被执行。条件语句创建语句块。如果给出的表达式是 true&#xff0c;执行块中的语句集&#xff0c;如果表达式为 false&#xff0c;则 else 块语句将最后执行。 序号条件语句1.if2.if-else3.if-else ladder4.unique if5.unique0 if6.p…

Redis7:商户查询缓存1

欢迎来到“雪碧聊技术”CSDN博客&#xff01; 在这里&#xff0c;您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者&#xff0c;还是具有一定经验的开发者&#xff0c;相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导&#xff0c;我将…

[FBCTF 2019]rceservice 详细题解

知识点: json字符串 PHP正则表达式元字符 PCRE回溯机制绕过正则表达式 %0a 换行符绕过正则表达式(详细讲解) 提示 Enter command as JSON 题目还有一个附件,打开是index.php文件源码 <?php putenv(PATH/home/rceservice/jail); if (isset($_REQUEST[cmd])) {$json $_…

九、HttpMessageConverter

文章目录 1. RequestBody2. RequestEntity3. ResponseBody4. SpringMVC处理json5. SpringMVC处理ajax6. RestController注解7. ResponseEntity 1. RequestBody 2. RequestEntity 3. ResponseBody 4. SpringMVC处理json 5. SpringMVC处理ajax 6. RestController注解 7. Response…

分享三个python爬虫案例

一、爬取豆瓣电影排行榜Top250存储到Excel文件 近年来&#xff0c;Python在数据爬取和处理方面的应用越来越广泛。本文将介绍一个基于Python的爬虫程序&#xff0c;用于抓取豆瓣电影Top250的相关信息&#xff0c;并将其保存为Excel文件。 获取网页数据的函数&#xff0c;包括以…

Redis - 数据库管理

Redis 提供了⼏个⾯向Redis数据库的操作&#xff0c;分别是dbsize、select、flushdb、flushall命令&#xff0c; 本机将通过具体的使⽤常⻅介绍这些命令。 一、切换数据库 select dbIndex 许多关系型数据库&#xff0c;例如MySQL⽀持在⼀个实例下有多个数据库存在的&#…

不加锁解决线程安全

不加锁解决线程安全 一、使用原子类&#xff08;Atomic Classes&#xff09; 原理&#xff1a; Java.util.concurrent.atomic 包提供了一系列原子类&#xff0c;如 AtomicInteger、AtomicLong、AtomicBoolean 等。这些原子类内部利用 CAS&#xff08;Compare and Swap&#xf…

Linux基础之病毒编写

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 声明&#xff1a;本文主要用作技术分享&#xff0c;所有内容仅供参考。任何使用或依赖于本文信息所造成的法律后果均与本人无关。请读者自行判断风险&#xff0c;并遵循相关法律法规。 感谢泷…