【设计模式:单例模式】单例模式02:懒汉模式
单例模式02:懒汉模式
正文开始@Assassin
目录:
- 单例模式02:懒汉模式
- 1. 回顾饿汉模式:
- 2. 懒汉模式细节:
- 3. 懒汉模式VS饿汉模式:
1. 回顾饿汉模式:
简单回顾一下单例模式中的饿汉模式~
我是饿汉模式!
所谓饿汉模式是指:只要类被加载,此对象gf
就会被创建,即使不使用gf
,它也会被创建,这是类的加载机制:只要调用了静态方法或属性,该方法或属性所在的类就会被加载,类加载之后便会首先初始化静态属性和静态代码块。
举个俗点的例子,就说你还没跟gf
相处很久,你俩还没来得及相互了解它便成了你的女朋友,也就是操之过急,像个饥饿的汉子一样,这便是饿汉模式的通俗理解。
这边还是具体举个栗子:
package com.haut.iot.assassin;//有一个类是GirlFriend
//假如你只能有一个女朋友
class GirlFriend {private String name; //姓名public static int n = 1; //静态变量//如何保障我们只能创建一个GirlFriend对象?//[单例模式 -> 饿汉模式]//1. 构造器私有化//2. 在类的内部创建对象(该对象需是static)//3. 向外提供一个静态的公共方法private static GirlFriend gf = new GirlFriend("王祖贤");//私有对象//为了在getInstance()返回gf,需将该方法修饰为staticpublic static GirlFriend getInstance() {return GirlFriend.gf; //返回gf}private GirlFriend(String name) { //构造器System.out.println("我是构造器,我被调用了!");this.name = name;}@Overridepublic String toString() { //重写toString()return "GirlFriend{" +"name='" + name + '\'' +'}';}
}public class SingleTon {public static void main(String[] args) {System.out.println(GirlFriend.n); //只使用了n这个静态变量,而没有使用gf对象}
}
可以看到在类中定义了一个static
的静态变量n
此时在测试类中使用类变量GirlFriend.n
,我们应该知道,当使用到类变量时,类加载器便会执行类加载,类加载的第一步便是初始化静态变量和静态代码块,如下图:
于是 private static GirlFriend gf = new GirlFriend("王祖贤");
便会被执行,也就是创建了GirlFriend
对象。
相应的也会调用构造方法,验证如下:
可以看到构造器的确被调用了,但并没有使用到gf
对象,这便很好地验证了饿汉模式的弊端:没有使用的需求,对象也被创建了
2. 懒汉模式细节:
懒汉模式的大概实现结构如下:
- 构造器私有化
- 创建一个
static
静态对象引用,并不直接new
出来对象 - 提供一个
public
的static
方法,可以得到一个Cat
对象 - 懒汉模式只有当程序员使用
getInstance()
方法时才返回对象,后面再次调用时会返回原对象,从而保证了单例
看这样一段代码: 可以看到static
的对象引用并没有引用实例,也就是在此并没有创建对象。
也就是说此时即使类被加载,构造器也不会被调用,构造器的调用是伴随着对象的创建而调用的,它的作用是初始化已经创建好的对象。
同样的,我们来验证一下:
package com.haut.iot.ninghai;//希望在程序运行过程中,只创建一个对象
//使用单例模式
class Cat {private String name;//名字private static Cat cat; //默认为nullpublic static int n = 100;//静态变量//1.构造器私有化//2.创建一个static静态对象//3.提供一个public的static方法,可以得到一个Cat对象private Cat(String name) {//构造器我们照样修饰成privateSystem.out.println("我是构造器,我被调用了~");this.name = name;}//getInstance()方法public static Cat getInstance() {if (cat == null) {cat = new Cat("小猫咪");}return cat;}
}//演示懒汉式的单例模式
public class SingleTon {public static void main(String[] args) {System.out.println(Cat.n);}
}
在类中同样定义了一个public
的static
类变量n
在测试类中通过类名来调用n
运行结果如下:
能清楚的看到这是输出了n
的值100,并没有调用构造器打印该语句:
也就是说,此时虽然类已经被加载了,但是并没有创建对象,这跟饿汉模式有着本质上的区别,大伙们自己去对比一哈~
那我们什么时候才能创建对象呢?
自行调用一下getInstance()
就好了~~
如下图所示:
执行结果:
源代码:
package com.haut.iot.ninghai;//希望在程序运行过程中,只创建一个对象
//使用单例模式
class Cat {private String name;//名字private static Cat cat; //默认为nullpublic static int n = 100;//静态变量//1.构造器私有化//2.创建一个static静态对象//3.提供一个public的static方法,可以得到一个Cat对象private Cat(String name) {//构造器我们照样修饰成privateSystem.out.println("我是构造器,我被调用了~");this.name = name;}//getInstance()方法public static Cat getInstance() {if (cat == null) {cat = new Cat("小猫咪");}return cat;}
}//演示懒汉式的单例模式
public class SingleTon {public static void main(String[] args) {System.out.println(Cat.n); //类变量Cat instance = Cat.getInstance(); //得到一个Cat对象}
}
为什么这样就好了呢?
我们来分析一波:
能清楚的看到,在getInstance()
里面逻辑是这样的:如果cat
为null
,就new
一个对象,如果不为空,直接返回原对象。因为cat
默认是为null
的,所以第一次调用getInstance()
时会创建一个Cat
对象,之后再调用就会返回源对象了,保证了一个类只有一个实例对象。
惯用套路,我们来实操一下:
package com.haut.iot.ninghai;//希望在程序运行过程中,只创建一个对象
//使用单例模式
class Cat {private String name;//名字private static Cat cat; //默认为nullpublic static int n = 100;//静态变量//1.构造器私有化//2.创建一个static静态对象//3.提供一个public的static方法,可以得到一个Cat对象private Cat(String name) {//构造器我们照样修饰成privateSystem.out.println("我是构造器,我被调用了~");this.name = name;}//getInstance()方法public static Cat getInstance() {if (cat == null) {cat = new Cat("小猫咪");}return cat;}@Overridepublic String toString() {return "Cat{" +"name='" + name + '\'' +'}';}
}//演示懒汉式的单例模式
public class SingleTon {public static void main(String[] args) {//System.out.println(Cat.n); //类变量Cat instance1 = Cat.getInstance(); //得到一个Cat对象System.out.println(instance1);Cat instance2 = Cat.getInstance();//单例模式,同一个对象System.out.println(instance2);//trueSystem.out.println(instance1 == instance2);}
}
运行结果:
3. 懒汉模式VS饿汉模式:
饿汉式VS懒汉式
- 二者最主要的区别在于创建对象的时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建
- 饿汉式不存在线程安全问题,懒汉式存在线程安全问题
- 饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题
- 在
javaSE
标准类中,java.lang.Runtime
就是经典的单例模式(饿汉模式)
简单分析一哈:
懒汉模式的线程安全问题主要体现在getInstance()
方法中。
假设同时有三个线程执行getInstance()
方法,这三个线程都进入了if
语句的判断中,当第一个线程判断为null
时,第二个线程也很快地执行了if
条件判断。 假设当第二个线程进到if中,第一个线程还没有创建好对象,那么第二个线程也会去创建新对象,因为此时判断为null
。 同理,第三个线程也是如此。这样一来就会造成同一时间点创建多个对象,显然这破坏了单例模式的规则。这个线程安全问题是可以解决的,以后再谈⑧
饿汉模式会造成资源的浪费是因为可能你的需求只是使用另一个模块,但是类的加载机制会把你不需要的工作给做好(创建对象),这样就造成了资源浪费,而懒汉式必须得自己调用才会创建对象,不存在浪费资源。
在JavaSE
中,java.lang.Runtime
中存在经典的单例模式,我们来看看源码:
很明显,这是一个饿汉式的单例模式。
【设计模式:单例模式】单例模式02:懒汉模式相关推荐
- 单例模式的实现-懒汉模式【大话设计模式之爱你一万年:单例模式:我的女朋友只有你一个】
2.单例模式的实现-懒汉模式 视频学习地址 -- <大话设计模式之爱你一万年>:https://dwz.cn/wqO0MAy7 这一节我们先来看看一种实现模式,懒汉模式,这也是这么中实现 ...
- 大话设计模式之爱你一万年:第二章 创建型模式:单例模式:我的女朋友只有你一个:2.单例模式的实现-懒汉模式
2.单例模式的实现-懒汉模式 视频学习地址 -- <大话设计模式之爱你一万年>:https://dwz.cn/wqO0MAy7 这一节我们先来看看一种实现模式,懒汉模式,这也是这么中实现 ...
- 单例模式的原理/懒汉模式/饿汉模式以及不同版本的单例模式程序
单例模式 单例模式定义 懒汉模式与饿汉模式 懒汉模式 饿汉模式 懒汉模式和饿汉模式的区别 懒汉模式的不同版本 版本一 版本二 版本三 版本四 单例模式定义 保证一个类仅有一个实例,并提供一个该实例的全 ...
- java设计模式之单例模式|单例模式之饿汉模式、懒汉模式、枚举方式|最详细的6种懒汉模式详解
目录 一.单例模式 二.饿汉模式和懒汉模式 1.饿汉模式,线程安全 2.懒汉模式 懒汉模式1,线程不安全(不常用) 懒汉模式2,线程安全(不常用) 懒汉模式3,线程安全,双重校验(不常用) 懒汉模式4 ...
- 设计模式复习-单例模式
#pragma once #include "stdafx.h" #include<set> #include<string> #include<io ...
- 【设计模式】单例模式 Singleton Pattern
通常我们在写程序的时候会碰到一个类只允许在整个系统中只存在一个实例(Instance) 的情况, 比如说我们想做一计数器,统计某些接口调用的次数,通常我们的数据库连接也是只期望有一个实例.Windo ...
- C++设计模式--单例模式详解(懒汉模式、饿汉模式、双重锁)
C++设计模式--单例模式详解(懒汉模式.饿汉模式.双重锁) 应用场景 一.单例模式是什么? 二.使用步骤 1.UML图 2.代码实现 应用场景 通常我们在做通讯的时候,我们跟服务器数据交互,假如每次 ...
- 2023-01-26 JS设计模式-单例模式:单例模式的原理和实现,懒汉模式和饿汉模式,单例模式实现登录框
文章目录 1.什么是单例模式? 介绍 特点 结构 2.如何实现一个单例模式? 思路 实现代码 3.单例模式的优缺点 4.懒汉模式和饿汉模式 懒汉模式:一开始不会实例化,什么时候用才new出来实例化 饿 ...
- 大聪明教你学Java设计模式 | 第一篇:单例模式 (懒汉模式和饿汉模式)
前言 大聪明在写代码的过程中发现设计模式的影子是无处不在,设计模式也是软件开发人员在软件开发过程中面临的一般问题的解决方案.大聪明本着"独乐乐不如众乐乐"的宗旨与大家分享一下设计模 ...
最新文章
- 海量无序数据寻找第 K 大的数
- 系统集成项目管理工程师软考辅导——3年真题透解与全真模拟
- 几个OpenSource的源代码管理软件
- UI5 libraries determined in Backend
- 保护 WordPress 安全的10个方法
- JavaScript 表单专题
- 中红外传感器行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
- 基于深度学习的数字识别GUI的设计
- fastadmin在html中查询数据,常见问题 · fastadmin 常见问题 · 看云
- ENVI学习总结(八)——图像镶嵌
- SpringMVC传递数组请求问题
- 学习通视频enc生成方法
- Wso2 api manager 帮助文档
- 变转速数据集 -- 渥太华轴承数据集描述及下载链接
- 看完电影《门锁》感觉脊背发凉,智慧园区带来安全感
- 仿B站的视频评论列表
- C语言程序设计之通讯录
- jQuery学习笔记(二)使用选择器一
- django一个html先后两个form,Django教程(三)- Django表单Form
- 题目42:一笔画问题