JAVA设计模式之单例模式详解
前言
在之前的文章里已经介绍了设计模式以及设计原则的概念,接下来我们从单例模式入手深入学习几种常用的JAVA设计模式,在实践中加深理解。
一、单例模式是什么?
单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。
作用:单例模式是保证系统实例唯一性的重要手段。用于一个全局类对象在多个地方被使用的场景下,保障了整个系统只有一个对象被使用,很好的节约了资源
实现方法:将类的实例化方法私有化来防止程序通过其他方式创建该类的实例,提供一个全局唯一获取该类实例的方法帮助用户获取类的实例。
实现单例模式很简单,每次获取前先判断系统是否已经存在单例对象,没有就创建,有就返回这个对象。单例模式常见的写法有懒汉式单例和饿汉式单例。
二、懒汉式单例
定义:类加载时没有生成单例,第一次调用 getlnstance 方法时创建这个单例。
public class LazySingleton { //定义一个私有的静态对象instance,静态方法和属性属于类,能保障单例对象的唯一性 private static LazySingleton instance; //私有化构造方法,只能在本类中被访问,其他类中不能通过构造方法直接创建对象 private LazySingleton() { } //提供一个全局唯一获取实例的方法 public static synchronized LazySingleton getInstance(){ if(instance==null){ instance=new LazySingleton(); } return instance; } }
懒汉模式在获取对象实例时做了加锁操作,因此是线程安全的
测试代码与结果
public class TestLazySingleton { public static void main(String[] args) { LazySingleton lazySingleton1=LazySingleton.getInstance(); LazySingleton lazySingleton2=LazySingleton.getInstance(); LazySingleton lazySingleton3=LazySingleton.getInstance(); System.out.println(lazySingleton1); System.out.println(lazySingleton2); System.out.println(lazySingleton3); } }
从上图中可以看出虽然获取了三次实例,但每次获取的都是同一个实例,即一个类只有一个实例。
三、饿汉式单例
定义:该模式的特点是类一旦加载就创建一个单例,在调用 getInstance 方法之前单例已经存在。
public class HungrySingleton { //类加载完成后该类的实例便已经存在 private static HungrySingleton instance=new HungrySingleton(); //私有化构造方法 private HungrySingleton(){ } //类加载后实例就存在,不会出现线程安全问题,不需要加锁 public static HungrySingleton getInstance(){ return instance; } }
测试代码和结果
public class TestHungrySingleton { public static void main(String[] args) { HungrySingleton hungrySingleton1=HungrySingleton.getInstance(); HungrySingleton hungrySingleton2=HungrySingleton.getInstance(); HungrySingleton hungrySingleton3=HungrySingleton.getInstance(); System.out.println(hungrySingleton1); System.out.println(hungrySingleton2); System.out.println(hungrySingleton3); } }
从上图看出饿汉式单例在整个运行过程中也只存在一个实例。
懒汉式单例和饿汉式单例的区别
1.懒汉模式在类中定义了单例但是并未实例化,实例化是在方法中实现的,而饿汉模式定义的时候就进行了实例化
2.懒汉模式需要在获取实例的方法上加锁保证线程安全,饿汉模式不需要加锁。
四、双重校验锁
懒汉模式用到了synchronized,会导致很大的性能开销,并且加锁其实只需要在第一次初始化的时候用到,之后的调用都没必要再进行加锁。
双重校验锁在懒汉模式的基础上做了进一步的优化,给静态对象加上volatile来保证有序性,第一次获取对象时通过synchronize(Singleton.class)保障操作的唯一性。
public class LockSingleton { private volatile static LockSingleton lockSingleton; private LockSingleton(){} public static LockSingleton getInstance(){ if(lockSingleton==null){ synchronized (LockSingleton.class){ if (lockSingleton==null){ lockSingleton=new LockSingleton(); } } } return lockSingleton; } }
测试代码与结果
public class LockTest { public static void main(String[] args) { LockSingleton lockSingleton1=LockSingleton.getInstance(); LockSingleton lockSingleton2=LockSingleton.getInstance(); LockSingleton lockSingleton3=LockSingleton.getInstance(); System.out.println(lockSingleton1); System.out.println(lockSingleton2); System.out.println(lockSingleton3); } }
执行双重检查是因为,如果多个线程同时了通过了第一次检查,并且其中一个线程首先通过了第二次检查并实例化了对象,那么剩余通过了第一次检查的线程就不会再去实例化对象。
除了第一次创建实例的时候会出现加锁的情况,后续的所有调用都会避免加锁而直接返回,解决了性能消耗的问题。
总结
关于单例模式本文介绍了懒汉模式、饿汉模式和双重校验锁。懒汉和饿汉模式的最大区别是定义实例的时候是否进行实例化。双重校验锁是对懒汉模式的优化,解决了性能消耗的问题。
到此这篇关于JAVA设计模式之单例模式详解的文章就介绍到这了,更多相关JAVA单例模式内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!
原文出处:https://blog.csdn.net/qq_52173163/article/details/122730828
相关文章
- 这篇文章主要介绍了如何利用java语言实现经典《复杂迷宫》游戏,文中采用了swing技术进行了界面化处理,感兴趣的小伙伴可以动手试一试...2022-02-01
java 运行报错has been compiled by a more recent version of the Java Runtime
java 运行报错has been compiled by a more recent version of the Java Runtime (class file version 54.0)...2021-04-01- 这篇文章主要介绍了在java中获取List集合中最大的日期时间操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了教你怎么用Java获取国家法定节假日,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下...2021-04-23
- 这篇文章主要介绍了Java如何发起http请求的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-31
- 说起C#和Java这两门语言(语法,数据类型 等),个人以为,大概有90%以上的相似,甚至可以认为几乎一样。但是在工作中,我也发现了一些细微的差别...2020-06-25
- 这篇文章主要介绍了解决Java处理HTTP请求超时的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-29
- 这篇文章主要介绍了java 判断两个时间段是否重叠的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了超简洁java实现双色球若干注随机号码生成(实例代码),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-02
- 这篇文章主要介绍了Java生成随机姓名、性别和年龄的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-01
java 画pdf用itext调整表格宽度、自定义各个列宽的方法
这篇文章主要介绍了java 画pdf用itext调整表格宽度、自定义各个列宽的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-31- 这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
Java使用ScriptEngine动态执行代码(附Java几种动态执行代码比较)
这篇文章主要介绍了Java使用ScriptEngine动态执行代码,并且分享Java几种动态执行代码比较,需要的朋友可以参考下...2021-04-15- 这篇文章主要介绍了Java开发实现人机猜拳游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-03
- 这篇文章主要介绍了Java List集合返回值去掉中括号('[ ]')的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-29
Java中lombok的@Builder注解的解析与简单使用详解
这篇文章主要介绍了Java中lombok的@Builder注解的解析与简单使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-06- 下面小编就为大家带来一篇java中String类型变量的赋值问题介绍。小编觉得挺不错的。现在分享给大家,给大家一个参考。...2016-03-28
Java 8 Stream 的终极技巧——Collectors 功能与操作方法详解
这篇文章主要介绍了Java 8 Stream Collectors 功能与操作方法,结合实例形式详细分析了Java 8 Stream Collectors 功能、操作方法及相关注意事项,需要的朋友可以参考下...2020-05-20- 这篇文章主要介绍了Java线程池中的各个参数如何合理设置操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-19
- 在Java中,我们可以利用多线程来最大化地压榨CPU多核计算的能力,下面这篇文章主要给大家介绍了关于java中多线程与线程池基本使用的相关资料,需要的朋友可以参考下...2021-09-13