单例模式——饿汉模式懒汉模式
目录
一、什么是单例模式?
二、单例模式的应用场景
三、两种典型的方式实现单例模式
1.饿汉模式
2.懒汉模式
3.理解懒汉模式和饿汉模式
四、单例模式和线程的关系
1.饿汉模式是否线程安全?
2.懒汉模式线程安全吗?为什么?
2.1 如何改进懒汉模式?让代码变得线程安全呢?
一、什么是单例模式?
单例模式是一种常见的“设计模式”
二、单例模式的应用场景
某个类,不应该有多个实例,此时就可以使用单例模式(DataSource就是一个典型的案例,一一个程序中只有一个实例,不应该实例化多个DataSource对象)。如果尝试创建多个实例,编译期就会报错。
三、两种典型的方式实现单例模式
1.饿汉模式
public class singlePattern {//先创建一个表示单例的类//我们就要求Singleton这个类只能有一个实例//饿汉模式的单例实现//饿汉模式的单例实现,“饿”指得是,只要类被加载,实例就会立刻创建(实例创建时机比较早)static class Singleton{//把 构造方法 变为私有,此时在该类外部,就无法 new 这个类的实例了private Singleton(){}
//再来创建一个 static 的成员,表示Singleton 类唯一的实例//static 和 类相关,和实例无关,类在内存中只有一份,static 成员也就只有一份static Singleton instance = new Singleton();//new没报错是因为Singleton类是singlePattern的内部类,singlePattern是可以访问内部类的private成员的public static Singleton getInstance(){return instance;}public static void main(String[] args) {
//此处得 getInstance 就是获取实例得唯一方式,不应该使用其他方式创建实例了Singleton s = Singleton.getInstance();Singleton s2 = Singleton.getInstance();System.out.println(s == s2);}
}}
只要类被加载,就会立刻实例化Singleton实例,后续无论怎么操作,只要严格使用getInstance,就不会出现其他实例。
2.懒汉模式
public class lazyPattern {//使用懒汉模式来实现,Singleton类被加载的时候,不会立刻实例化//等到第一次使用这个实例的时候,再实例化static class Singleton{private static Singleton instance = null;public static Singleton getInstance(){if(instance == null){instance = new Singleton();}return instance;}}public static void main(String[] args) {}
}
类被加载的时候,没有立刻被实例化,第一次调用getInstance的时候,才真正的实例化。
如果要是代码一整场都没有调用getInstance,此时实例化的过程也就被省略掉了,又称“延时加载”
一般认为“懒汉模式” 比 “饿汉模式”效率更高。
懒汉模式有很大的可能是“实例用不到”,此时就节省了实例化的开销。
3.理解懒汉模式和饿汉模式
各种编辑器,有两种主要的打开方式:
- 记事本,会尝试把整个文件的内容都读取到内存中,然后再展示给用户(饿汉模式)
- vscode/sublime,只是会把当前这个屏幕内的内容(以及周围的一小点内容)加载到内存中,随着翻页,会继续加载
四、单例模式和线程的关系
1.饿汉模式是否线程安全?
安全。
类加载只有一次机会,不可能并发执行,对于饿汉模式来说,多线程同时调用getInstance,由于getInstance里只做了一件事:读取instance实例的地址=》多个线程在同时读取同一个变量,不会产生线程不安全。
2.懒汉模式线程安全吗?为什么?
懒汉模式是线程不安全的,只有在实例化之前调用,存在线程不安全问题
如果要是已经把实例创建好了~后面再去并发调用getInstance 就是线程安全的了
以上面的懒汉模式代码为例,多线程并发执行的时间线如下。
2.1 如何改进懒汉模式?让代码变得线程安全呢?
1.加锁
public class lazyPatternToSafe {static class Singleton{private static Singleton instance = null;//方法一:public static Singleton getInstance1(){synchronized (lazyPattern.Singleton.class){if(instance == null){instance = new Singleton();}}return instance;}//方法二:synchronized public static Singleton getInstance2(){if(instance == null){instance = new Singleton();}return instance;}}
}
上面的“粒度”较小,下面的“粒度”较大。
加锁之后的时间线:
但是加锁之后,仍然存在效率问题。上面的改进代码,哪怕实例已经创建好了,但是每次调用getInstance还是涉及加锁解锁,而这里的加锁解锁已经不必要了。只要代码中涉及到锁,基本上就和高性能无缘了(因为涉及到锁之间的等待)
2.解决方案:只有在实例化之前调用的时候加锁,后面不加锁~
static class Singleton {private static Singleton instance = null;public static Singleton getInstance1() {if(instance == null){synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
上述双线程执行的时间线如下:
此时即能保证线程安全,也能保证程序运行的效率。
3.但是还是存在问题,此处的多个操作,可能会被编译器优化,只有第一次读才从内存中读取,后续的读就直接从CPU中读取寄存器。就可能导致线程1修改之后,线程2没有读到最新的值,内存可见性导致的线程不安全问题(先加锁的线程在修改,后加锁的线程在读取)。
最终版本:加volatile关键字
static class Singleton {//为了解决内存不可见问题,需要加上关键字volatileprivate volatile static Singleton instance = null;public static Singleton getInstance1() {if(instance == null){synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}
上面的代码:为了保证线程安全,涉及到三个要点:
1.加锁 【保证线程安全】
2.双重if 【保证效率】
3.volatile【避免内存可见性引来的问题】
单例模式——饿汉模式懒汉模式相关推荐
- DBCP使用BasicdataSource连接(两种单例模式-----饿汉和懒汉模式)
DBCP使用BasicDataSource连接 BasicDataSource实现DataSource的接口,可以进行简单的数据库连接 第一种:懒汉模式:顾名思义,"懒",只有在调 ...
- 单例模式 (饿汉、懒汉)
单例模式 定义 单例模式的实现 饿汉模式 懒汉模式 线程安全问题分析: 如何解决线程安全问题?? 关键点总结 定义 单例模式,是一种常见的"设计模式" 设计模式: 设计模式是一套经 ...
- 单例模式之饿汉、懒汉模式
目录 1.单例模式 1.1 饿汉模式 1.2 懒汉模式 1.单例模式 单例模式能保证类在程序中只存在唯一一份实例.这一点在很多场景中都需要,比如JDBC中的DataSource实例就只需要一个. 单例 ...
- 单例模式之饿汉和懒汉(java)
文章目录 1.前言 2.怎么区分饿汉和懒汉模式 3. 饿汉 4.懒汉 (双重检查 Double Check Lock) 5.饿汉模式在JDK中的应用(Runtime) 6.相关文章 1.前言 面试时, ...
- C++设计模式--单例模式详解(懒汉模式、饿汉模式、双重锁)
C++设计模式--单例模式详解(懒汉模式.饿汉模式.双重锁) 应用场景 一.单例模式是什么? 二.使用步骤 1.UML图 2.代码实现 应用场景 通常我们在做通讯的时候,我们跟服务器数据交互,假如每次 ...
- 单例模式饿汉模式与懒汉模式
目录 1.什么是单例模式 2.为什么需要单例模式? 3.如何实现单例模式 3.1饿汉方式 3.2懒汉模式 1.什么是单例模式 单例模式是一种设计模式,单例模式能保证某个类在程序中只存在唯一一份实例, ...
- 单例模式之饿汉模式懒汉模式
前言 单例模式能保证某个类在程序中只存在唯一一份实例,而不会创建出多个实例,比如 JDBC 中的 DataSource 实例就只需要一个.单例模式具体的实现方式有"饿汉" 和 &q ...
- Singleton模式(单例模式) 饿汉式和懒汉式
目的:整个应用中有且只有一个实例,所有指向该类型实例的引用都指向这个实例. 好比一个国家就只有一个皇帝(XXX),此时每个人叫的"皇帝"都是指叫的XXX本人; 常见单例模式类型: ...
- 单例模式,饿汉与懒汉
文章目录 什么是单例模式 单例模式的两种形式 饿汉模式 懒汉模式 懒汉模式与饿汉模式是否线程安全 懒汉模式的优化 什么是单例模式 单例模式其实就是一种设计模式,跟象棋的棋谱一样,给出一些固定的套路帮助 ...
- Java-Day12 面向对象的三大特征之封装、继承,单例模式(饿汉式、懒汉式)、方法重写 (覆盖)、注解 (annotation)、super关键字、对象的创建流程超详细
目录 1. 面向对象的三大特征之封装 1.1 封装的含义 1.2 封装的目的 1.3 封装的优点 1.4 封装的实现过程 1.5 拓展知识:JavaBean 2. 面向对象的三大特征之继承 2.1 继 ...
最新文章
- linux.调整收发队列,linux消息队列通信
- 20165318 结对编程项目-四则运算 阶段总结
- sonarqube+jenkins 构建代码质量管理平台
- Pandas dtypes
- Java基础学习总结(67)——Java接口API中使用数组的缺陷
- Android Studio导入so文件到项目中
- 2.4 使用ARDUINO控制MC20进行GPS数据的获取和解析
- 一、华为设备telnet命令配置
- AI头发笔刷_这么棒的AI插件,一定要偷偷藏好了不让总监知道……
- Unity制作简单动画效果
- Xpose 建立新工程
- TA入门笔记(十五)
- AIS数据修复-三次样条插值法(Cubic spline interpolation)
- 如何下载OpenJDK安装版本
- html文字多余部分三个点,解决特殊符号和字母换行问题
- VB中ByVal与ByRef有什么区别
- 广电电视信号如何生成RTMP流进入流媒体系统网络分发实现手机APP播放
- c语言编程杨辉三角形流程图,使用c语言输出杨辉三角形的简单方法
- 写给所有程序员的心声~千里马常有,但伯乐不常有
- SpringMVC 13. RESTful CRUD