ug环球官方网:重学 Java 设计模式:实战单例模式

admin/2020-06-02/ 分类:科技/阅读:


作者:小傅哥
博客:https://bugstack.cn

沉淀、分享、发展,让自己和他人都能有所收获!

一、前言

5个建立型模式的最后一个

在设计模式中根据差别的处置方式共包罗三大类;建立型模式结构型模式行为模式,其中建立型模式现在已经先容了其中的四个;工厂方式模式抽象工厂模式天生器模式原型模式,除此之外另有最后一个单例模式

掌握了的知识才是自己的

在本次编写的重学 Java 设计模式的编写中尽可能多的用种种场景案例还先容设计的使用,包罗我们已经使用过的场景;种种类型奖品发放多套Redis缓存集群升级装修公司报价清单百份考卷问题与谜底乱序,通过这些场景案例的实践感受设计模式的头脑。但这些场景都是作者通过履历分离出来的,还并不是读者的知识,以是你若是希望可以融会贯通的掌握那么一定要亲力亲为的操作,事必躬亲的完成。

书不是看的是用的

在这里照样想强调一下学习方式,总有许多小伙伴对学习知识有疑惑,显著看了、看的时刻也懂了,但到了实际使用的时刻却用不上。或者有时刻在想是不要是有加倍生动的漫画或者什么对比会好些,固然这些方式可能会加速一个新人对知识的明白速率。但只要你把学习视频当影戏看、学习书籍当故事看,就很难掌握这项手艺栈。只有你把它用起来,逐字逐句的深挖,一点点的寻找,把各项遇到的盲点所有扫清,才能让你真的掌握这项技术。

二、开发环境

  1. JDK 1.8
  2. Idea Maven
  3. 涉及工程1个,可以通过关注民众号bugstack虫洞栈,回复源码下载获取(打开获取的链接,找到序号18)

三、单例模式先容

单例模式可以说是整个设计中最简朴的模式之一,而且这种方式纵然在没有看设计模式相关资料也会常用在编码开发中。

由于在编程开发中经常会遇到这样一种场景,那就是需要保证一个类只有一个实例哪怕多线程同时接见,并需要提供一个全局接见此实例的点。

综上以及我们平时的开发中,可以总结一条履历,单例模式主要解决的是,一个全局使用的类频仍的建立和消费,从而提升提升整体的代码的性能。

四、案例场景

本章节的手艺所泛起的场景异常简朴也是我们一样平常开发所能见到的,例如;

  1. 数据库的连接池不会频频建立
  2. spring中一个单例模式bean的天生和使用
  3. 在我们平时的代码中需要设置全局的的一些属性保留

在我们的一样平常开发中大致上会泛起如上这些场景中使用到单例模式,虽然单例模式并不庞大然则使用面却比较广。

五、7种单例模式实现

单例模式的实现方式比较多,主要在实现上是否支持懒汉模式、是否线程平安中运用各项技巧。固然也有一些场景不需要思量懒加载也就是懒汉模式的情形,会直接使用static静态类或属性和方式的方式举行处置,供外部挪用。

那么接下来我们就通过实现差别方式的实现举行解说单例模式。

0. 静态类使用

public class Singleton_00 { public static Map<String,String> cache = new ConcurrentHashMap<String, String>(); } 
  • 以上这种方式在我们平时的营业开发中异常场常见,这样静态类的方式可以在第一次运行的时刻直接初始化Map类,同时这里我们也不需要到延迟加载在使用。
  • 在不需要维持任何状态下,仅仅用于全局接见,这个使用使用静态类的方式加倍利便。
  • 但若是需要被继续以及需要维持一些特定状态的情形下,就适合使用单例模式。

1. 懒汉模式(线程不平安)

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
  • 现在此种方式的单例确实知足了懒加载,然则若是有多个接见者同时去获取工具实例你可以想象成一堆人在抢茅厕,就会造成多个同样的实例并存,从而没有到达单例的要求。

2. 懒汉模式(线程平安)

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(); } } 
  • 此种模式虽然是平安的,但由于把锁加到方式上后,所有的接见都因需要锁占用导致资源的虚耗。若是不是特殊情形下,不建议此种方式实现单例模式。

3. 饿汉模式(线程平安)

public class Singleton_03 { private static Singleton_03 instance = new Singleton_03(); private Singleton_03() { } public static Singleton_03 getInstance() { return instance; } } 
  • 此种方式与我们开头的第一个实例化Map基本一致,在程序启动的时刻直接运行加载,后续有外部需要使用的时刻获取即可。
  • 但此种方式并不是懒加载,也就是说无论你程序中是否用到这样的类都会在程序启动之初举行建立。
  • 那么这种方式导致的问题就像你下载个游戏软件,可能你游戏舆图还没有打开呢,然则程序已经将这些舆图所有实例化。到你手机上最显著体验就一开游戏内存满了,手机卡了,需要换了。

4. 使用类的内部类(线程平安)

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; } } 
  • 使用类的静态内部类实现的单例模式,既保证了线程平安有保证了懒加载,同时不会由于加锁的方式花费性能。
  • 这主要是由于JVM虚拟机可以保证多线程并发接见的准确性,也就是一个类的组织方式在多线程环境下可以被准确的加载。
  • 此种方式也是异常推荐使用的一种单例模式

5. 双重锁校验(线程平安)

public class Singleton_05 { private volatile static 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; } } 
  • 双重锁的方式是方式级锁的优化,减少了部门获取实例的耗时。
  • 同时这种方式也知足了懒加载。
  • volatile关键字会强制的保证线程的可见性,而不加这个关键字,JVM也会全力去保证可见性,但若是CPU一直处于忙碌状态就不确定了。

6. CAS「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@2b193f2d System.out.println(Singleton_06.getInstance()); // org.itstack.demo.design.Singleton_06@2b193f2d } } 
  • java并发库提供了许多原子类来支持并发接见的数据平安性;AtomicIntegerAtomicBooleanAtomicLongAtomicReference
  • AtomicReference 可以封装引用一个V实例,支持并发接见如上的单例方式就是使用了这样的一个特点。
  • 使用CAS的利益就是不需要使用传统的加锁方式保证线程平安,而是依赖于CAS的忙等算法,依赖于底层硬件的实现,来保证线程平安。相对于其他锁的实现没有线程的切换和壅闭也就没有了分外的开销,而且可以支持较大的并发性。
  • 固然CAS也有一个瑕玷就是忙等,若是一直没有获取到将会处于死循环中。

7. Effective Java作者推荐的枚举单例(线程平安)

public enum Singleton_07 { INSTANCE; public void test(){ System.out.println("hi~"); } } 

约书亚·布洛克(英语:Joshua J. Bloch,1961年8月28日-),美国著名程序员。他为Java平台设计并实作了许多的功效,曾担任Google的首席Java架构师(Chief Java Architect)。

  • Effective Java 作者推荐使用枚举的方式解决单例模式,此种方式可能是平时最少用到的。
  • 这种方式解决了最主要的;线程平安、自由串行化、单一实例。

挪用方式

@Test public void test() { Singleton_07.INSTANCE.test(); 

这种写法在功效上与共有域方式相近,然则它更简练,无偿地提供了串行化机制,绝对防止对此实例化,纵然是在面临庞大的串行化或者反射攻击的时刻。虽然这中方式还没有普遍接纳,然则单元素的枚举类型已经成为实现Singleton的最佳方式。

但也要知道此种方式在存在继续场景下是不可用的。

六、总结

  • 虽然只是一个很平时的单例模式,但在种种的实现上真的可以看到java的基本功的体现,这里包罗了;懒汉、饿汉、线程是否平安、静态类、内部类、加锁、串行化等等。
  • 在平时的开发中若是可以确保此类是全局可用不需要做懒加载,那么直接建立并给外部挪用即可。但若是是许多的类,有些需要在用户触发一定的条件后(游戏关卡)才显示,那么一定要用懒加载。线程的平安上可以按需选择。
  • 建议在学习的历程中一定要加以实践,否则很难完完整整的掌握一整套的知识系统。例如案例中的泛起的Effective Java一书也异常建议人人阅读。另外推荐下这位大神的Github:https://github.com/jbloch

七、推荐阅读

  • 重学 Java 设计模式:实战原型模式-模拟考试试卷乱序问题和谜底
  • Java开发架构篇:初识领域驱动设计DDD落地
  • Java开发架构篇:DDD模子领域层决议规则树服务设计
  • Java开发架构篇:领域驱动设计架构基于SpringCloud搭建微服务
  • 源码剖析(面试常问问题) | Mybatis接口没有实现类为什么可以执行增删改查
  • 讲道理,只要你是一个爱折腾的程序员,结业找工作真的不需要再花钱培训!
,

Allbet

www.xaks68887722.com欢迎进入欧博开户平台(Allbet Gaming),欧博开户平台开放欧博(Allbet)开户、欧博(Allbet)代理开户、欧博(Allbet)电脑客户端、欧博(Allbet)APP下载等业务

TAG:
阅读:
广告 330*360
广告 330*360
Sunbet_进入申博sunbet官网
微信二维码扫一扫
关注微信公众号
新闻自媒体 Copyright © 2002-2019 Sunbet 版权所有
二维码
意见反馈 二维码