java基础之设计模式之单例模式
关于单例模式:
单例,即单一实例。因为在一些情况下,某些类的对象,我们只需要一个就可以了,所以我们要用到单例模式。
单例模式的目的是使得一个类中的一个静态对象成为系统中的唯一实例,提供一个访问该实例的方法。并阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
单例模式特点:其在整个应用程序的生命周期中只存在一个实例。
单例模式分为懒汉式和饿汉式两种
这里先贴出代码,然后再做解释,便于理解。
懒汉式单例模式核心代码:
1 package com.wxb.singleton;
2
3 public class Singleton_Lazy {
4 /* --创建私有静态的自身实例对象-- */
5 private static Singleton_Lazy uniqueInstance = null;
6
7 /* --私有的构造方法,避免外界利用构造方法创建多个实例-- */
8 private Singleton_Lazy() {
9
10 }
11
12 /* --获取静态实例的方法--
13 * --该方法是静态的,可以通过类名直接调用--
14 */
15 public static Singleton_Lazy getUniqueInstance() {
16 if (null == uniqueInstance) {
17 uniqueInstance = new Singleton_Lazy();
18 }
19 return uniqueInstance;
20 }
21 }
懒汉式单例模式特点:懒汉模式的单例类的唯一实例对象是在第一次使用 getUniqueInstance()时实例化的。如果我们不调用 getUniqueInstance()的话,这个实例是不会存在的,即为 初始值null。可以看出如果不去动它的话,它自己是不会实例化的,所以形象的称之为懒汉模式。
饿汉式单例模式核心代码:
1 package com.wxb.singleton;
2
3 public class Singleton_Hungry {
4 /*
5 * --在初始化时,就实例化了静态的自身实例对象-- --饿汉式的缺点也在于此:浪费内存--
6 */
7 private static Singleton_Hungry uniqueInstance = new Singleton_Hungry();
8
9 /* --私有的构造方法,避免外界利用构造方法创建多个实例-- */
10 private Singleton_Hungry() {
11
12 }
13
14 /* --获取静态实例的方法--
15 * --该方法是静态的,可以通过类名直接调用--
16 */
17 public static Singleton_Hungry getUniqueInstance() {
18 return uniqueInstance;
19 }
20 }
饿汉单例模式特点:之所以称之为饿汉,是因为肚子饿了,人也会变得主动了,所以饿汉模式下的单例类其自己就会主动实例化该单例类的唯一实例对象。
一般懒汉式单例模式较为常用。
对于唯一实例的验证:
1 package com.wxb.singleton;
2
3 public class SingletonTest {
4 /* --单例模式唯一实例的测试|调用懒汉式单例验证-- */
5 public static void main(String[] args) {
6 Singleton_Lazy singleton_Lazy1 = Singleton_Lazy.getUniqueInstance();
7 Singleton_Lazy singleton_Lazy2 = Singleton_Lazy.getUniqueInstance();
8 if (singleton_Lazy1.equals(singleton_Lazy2)) {
9 System.out.println("Singleton_Lazy1 and singleton_Lazy2 are the same instance");
10 }
11 else {
12 System.out.println("Singleton_Lazy1 and singleton_Lazy2 are different instance");
13 }
14 }
15 }
输出结果:
可以看出虽然两次调用getUniqueInstance(),但是访问的是同一个实例。
对于懒汉式单例模式,还存在着多线程安全问题
在多线程中,如果在一开始调用 GetUniqueInstance()时,是由两个线程同时调用的,这样的话,两个线程均会进入GetUniqueInstance(),而后由于是第一次调用 GetUniqueInstance(),所以静态变量 uniqueInstance为 null ,这样的话,就会让两个线程均通过 if 语句的条件判断,然后调用 new GetUniqueInstance()了。
所以问题就出来了,因为有两个线程,所以会创建两个实例,这便违反了单例模式的初衷,使得单例模式在多线程中出现不安全的问题。
这个问题我们可以通过线程锁机制对单例模式做相应的优化,即先将一个线程锁定,然后等这个线程完成以后,再让其他的线程访问GetUniqueInstance()中的 if 段语句。
双重校验锁形式单例模式核心代码:
1 package com.wxb.singleton;
2
3 public class Singleton_Lazy_Safe {
4 /* --创建私有静态的自身实例对象-- */
5 private static Singleton_Lazy_Safe uniqueInstance = null;
6
7 /* --私有的构造方法,避免外界利用构造方法创建多个实例-- */
8 private Singleton_Lazy_Safe() {
9
10 }
11
12 /* --获取静态实例的方法--
13 * --该方法是静态的,可以通过类名直接调用--
14 */
15 public static Singleton_Lazy_Safe getUniqueInstance() {
16 /* --双重校验锁-- */
17 if (null == uniqueInstance) {
18 synchronized (Singleton_Lazy_Safe.class) {
19 if (null == uniqueInstance) {
20 uniqueInstance = new Singleton_Lazy_Safe();
21 }
22 }
23 }
24 return uniqueInstance;
25 }
26 }
关于使用双重校验的原因:
如果有两个线程同时到达,即同时调用了GetUniqueInstance(),此时由于 uniqueInstance == null ,所以两个线程都可以通过第一重的 singleton == null 校验,
进入第一重 if 语句后,由于存在锁机制,所以会有一个线程进入 lock 语句并进入第二重 uniqueInstance == null ,而另外的一个线程则会在 synchronized 语句的外面等待。
当第一个线程执行完 new Singleton_Lazy_Safe()语句后,便会退出锁定区域,此时,第二个线程便可以进入synchronized语句块,此时,如果没有第二重 uniqueInstance == null 的话,那么第二个线程还会继续调用 new Singleton_Lazy_Safe()语句,这样第二个线程又会创建一个 Singleton 实例,违反了“唯一实例”。
由于饿汉式单例类类被加载的时候,就会自行初始化uniqueInstance这个静态的自身实例对象。而不是在第一次调用GetUniqueInstance()时再来实例化单例类的唯一实例,所以饿汉式单例不需要编写多线程安全代码。
java基础之设计模式之单例模式的更多相关文章
- 第二十七节:Java基础面向对象-静态,单例模式,继承详情知识点
前言 Java基础面向对象-静态,单例模式,继承详情知识点.静态-static关键字,static变量,静态代码块,代码块(不加静态),对象创建过程,单例模式,继承. 静态-static关键字 // ...
- java 23 - 2 设计模式之单例模式
单例模式:保证类在内存中只有一个对象. 如何保证类在内存中只有一个对象呢? A:把构造方法私有 B:在成员位置自己创建一个对象 C:通过一个公共的方法提供访问 单例模式之饿汉式: (一进来就造对 ...
- Java基础-单列设计模式
概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...
- Java进阶篇设计模式之一 ----- 单例模式
前言 在刚学编程没多久就听说过设计模式的大名,不过由于当时还是个彻彻底底的菜鸟,并没有去触碰.直到在开始工作中对简单的业务代码较为熟悉之后,才正式的接触设计模式.当时最早接触的设计模式是工厂模式,不过 ...
- Java中的设计模式之单例模式
Java中的单例模式 设计模式是软件开发过程中经验的积累 一.单例模式 1.单例模式是一种常用的软件设计模式,通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控 ...
- Java基础-工厂设计模式(三锅的肥鸡)
---恢复内容开始--- 1)还没有工厂时代:假如还没有工业革命,如果一个你要一架飞机,一般的做法是自己去建造一架飞机,然后拿来开 通常的结果就是 有些时候 要么专科螺钉 没打好 要么就是 那个 ...
- JAVA基础—适配器设计模式
适配器概念 在计算机编程中,适配器模式将一个类的接口适配成用户所期待的.使用适配器,可以使接口不兼容而无法在一起工作的类协调工作,做法是将类自己包裹在一个已经存在的类中. JDK对适配器设计模式的应用 ...
- [Java面经]干货整理, Java面试题(覆盖Java基础,Java高级,JavaEE,数据库,设计模式等)
如若转载请注明出处: http://www.cnblogs.com/wang-meng/p/5898837.html 谢谢.上一篇发了一个找工作的面经, 找工作不宜, 希望这一篇的内容能够帮助到大 ...
- 【Java基础】Java设计模式简介
什么是设计模式 设计模式(Design pattern)是一套被反复使用.被多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性.设计 ...
随机推荐
- Oracle导出导入dmp文件(exp.imp命令行)
1.说明 使用Oracle命令行导出导入dmp文件, 从而在两个数据库之间快速转移数据, 也可以用来作为数据库的备份, 将来可以快速恢复数据. 命令:导出exp.导入imp 步骤: 使用Oracle的 ...
- IIS部署.net core项目
1.安装AspNetCoreModule模块 与ASP.NET时代不同,ASP.NET Core不再是由IIS工作进程(w3wp.exe)托管,而是使用自托管Web服务器(Kestrel)运行,中间最 ...
- 初识python 之 爬虫:爬取豆瓣电影最热评论
主要用到lxml的etree解析网页代码,xpath获取HTML标签. 代码如下: 1 #!/user/bin env python 2 # author:Simple-Sir 3 # time:20 ...
- 在CentOS7 安装 jq
root@: 安装EPEL源: yum install epel-release 安装完EPEL源后,可以查看下jq包是否存在: yum list jq 安装jq: yum install jq 命令 ...
- centos7 重定向符号
这篇只记录使用对应的使用方法,原理后期更新 >> 追加输出 <<追加输入 >输出 <输入 将正确和错误信息同事保留到一个文件 echo "this is ...
- Centos更换阿里云源
1.备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2.下载新的CentOS-Base ...
- vue3.0+vite项目搭建
npm init vite-app <project-name> cd <project-name> 根据控制台的提示执行: npm install / yarn npm ru ...
- js实现工具函数中groupBy数据分组
数据 this.tableData = [ {id: 1, name: '测试', number: 1, price: 0}, {id: 2, name: '测试', number: 1, price ...
- spring源码之refresh第二篇
大家好,我是程序员田同学 上篇文章对spring核心启动方法refresh做了整体的解读,但是只是泛泛而谈,接下来会出一系统文章对每个方法的源码进行深刻解读. 第一篇文章见 spring源码之方法概览 ...
- access偏移注入原理
前言:近段时间在学习access偏移注入时,在网上查询了大量的资料,感觉很多资料讲解的十分模糊并且我个人认为有很多不够严谨的地方,于是我便在线下经过大量测试,写出以下文章,如有错误,望指出. 如要转载 ...