项目github地址:bitcarmanlee easy-algorithm-interview-and-practice
欢迎大家star,留言,一起学习进步

单例模式是实际项目中使用最多的一种设计模式,有着非常广泛的使用场景。下面我们就结合一个实际项目中的例子,来说说单例模式的使用方式。

1.经典单例模式之懒汉模式

import java.util.HashMap;
import java.util.Map;public class Singleton {private static Map<String, String> testMap = new HashMap<String, String>();private static Singleton instance;private Singleton() {initTestMap();}public static void initTestMap() {for(int i=0; i<10; i++) {String value = "a" + String.valueOf(i);testMap.put(String.valueOf(i), value);}}public static Singleton getInstance() {if(instance == null) {instance = new Singleton();}return instance;}}

这个单例对象里面有一个testMap,我们希望Singleton对象初始化的时候testMap就已经初始化。
注意的几个点是:
1.instance对象与testMap对象均为static对象,这样可以直接用类名调用。
2.在构造方法中,将testMap初始化。

2.饿汉模式

import java.util.HashMap;
import java.util.Map;public class Singleton {private static Map<String, String> testMap = new HashMap<String, String>();private static Singleton instance = new Singleton();private Singleton() {initTestMap();}public static void initTestMap() {for(int i=0; i<10; i++) {String value = "a" + String.valueOf(i);testMap.put(String.valueOf(i), value);}}public static synchronized Singleton getInstance() {return instance;}}

饿汉模式与懒汉模式相比较起来,一上来就直接将实例初始化,不存在延迟加载的问题。

上面的两种写法,没有考虑多线程的情况。如果是在多线程的场景下使用,请参考后面的文章。

3.双重锁校验(double checked locking pattern)

双重检验锁模式(double checked locking pattern),是一种使用同步块加锁的方法。程序员称其为双重检查锁,因为会有两次检查 instance == null,一次是在同步块外,一次是在同步块内。为什么在同步块内还要再检验一次?因为可能会有多个线程一起进入同步块外的 if,如果在同步块内不进行二次检验的话就会生成多个实例了。

public class Singleton {private static Singleton instance;private Singleton() {}public static  Singleton getInstance() {if(instance == null) {synchronized(Singleton.class) {if(instance == null) {instance = new Singleton();}}}return instance;}
}

这段代码看起来很完美,很可惜,它是有问题。主要在于instance = new Singleton()这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。

1.给 instance 分配内存
2.调用 Singleton 的构造函数来初始化成员变量
3.将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)
但是在 JVM 的即时编译器中存在指令重排序的优化。也就是说上面的第二步和第三步的顺序是不能保证的,最终的执行顺序可能是 1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,然后顺理成章地报错。

我们只需要将 instance 变量声明成 volatile 就可以了。

public class Singleton {private volatile static Singleton instance;private Singleton() {}public static Singleton getInstance() {if(instance == null) {synchronized(Singleton.class) {if(instance == null) {instance = new Singleton();}}}return instance;}
}

volatile用在多线程,同步变量。 线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B。只在某些动作时才进行A和B的同步。因此存在A和B不一致的情况。volatile就是用来避免这种情况的。volatile告诉jvm, 它所修饰的变量不保留拷贝,直接访问主内存中的(也就是上面说的A)

参考文章:
http://wuchong.me/blog/2014/08/28/how-to-correctly-write-singleton-pattern/

单例模式(Singleton mode)实战讲解相关推荐

  1. python3中的单例模式Singleton

    #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2019-01-21 09:09:09 # @Author : cdl (1217096 ...

  2. Android设计模式——单例模式(Singleton)

    二十三种设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元 ...

  3. SpringBoot2.x整合redis实战讲解

    SpringBoot2.x整合redis实战讲解 简介:使用springboot-starter整合reids实战 1.官网:https://docs.spring.io/spring-boot/do ...

  4. 【设计模式】单例模式 Singleton Pattern

    通常我们在写程序的时候会碰到一个类只允许在整个系统中只存在一个实例(Instance)  的情况, 比如说我们想做一计数器,统计某些接口调用的次数,通常我们的数据库连接也是只期望有一个实例.Windo ...

  5. python单例_Python - 单例模式(Singleton)

    单例模式(Singleton) 本文地址: http://blog.csdn.net/caroline_wendy/article/details/23374575 单例模式 , 类的实例从始至终, ...

  6. ant4 多个form 验证_爬虫遇到头疼的验证码?Python实战讲解弹窗处理和验证码识别...

    点击上方"早起Python",关注并"星标" 每日接收Python干货! 本文含 3321 字,9代码片段建议阅读 8 分钟 前言 在我们写爬虫的过程中,目标网 ...

  7. 设计模式之单例模式——Singleton

                        设计模式之单例模式--Singleton 设计意图: 保证类仅有一个实例,并且可以供应用程序全局使用.为了保证这一点,就需要这个类自己创建自己的对象,并且对外有 ...

  8. 设计模式之——单例模式(Singleton)的常见应用场景(转):

    单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此 ...

  9. CSS中选择器优先级顺序实战讲解

    原文:CSS中选择器优先级顺序实战讲解 我们有些程序猿在给一个元素(比如div)应用样式的时候,会有一些疑问,为什么我写在后面的样式不能覆盖前面的样式呢,不是说CSS是层叠样式表吗? 如果你在开发中也 ...

  10. 海底捞月战法实战讲解

    海底捞月战法实战讲解 海底捞月: 股价经过放量强劲上升,一般用中阳线或涨停板有效突破半年线或年线等长期均线,随后股价快速地缩量回调至半年线或年线之下,在中阳线或涨停板的启动点获得支持,接下来股价往往能 ...

最新文章

  1. 零基础学oracle pdf_零基础学动漫插画详细步骤大全
  2. M-point moving-average(M点滑动平均)Matlab 实现
  3. ul li前面的点怎么变大_亚马逊产品被投诉需要UL认证,该如何办理?
  4. WebMagic学习总结
  5. python3生成随机数_python3实现随机数
  6. 练习题︱streamlit + opencv/YOLOv3 快速构建自己的图像目标检测demo网页
  7. 需求分析报告或需求调研报告和需求规格说明书有什么区别?
  8. office转换为还原度高的html,使用Aspose把office文件转换为Html文件及生成文件浏览乱码的解决...
  9. ggplot画世界地图
  10. 自学前端开发,现在手握大厂offer,我的故事还在继续
  11. tensorflow2.0之one_hot函数使用
  12. Android项目实战系列—基于博学谷(四)我的模块(上)
  13. 四象限运行模式_双向可控硅四象限触发方式介 - 双向可控硅四象限触发方式介绍_双向可控硅触发电路的设计...
  14. mt管理器没root执行脚本,mt管理器怎么执行脚本
  15. “贫民窟”下的农民工
  16. 青铜变王者,桌面云是如何逆袭的?
  17. c语言输出斐波那契数列前20项,在c语言中,如何利用数组求斐波那契数列的前20项?...
  18. Python在基金定投上的验证
  19. 探究大脑的保护层-血脑屏障是存在于毛细血管与脑组织之间的一层特殊的保护屏障,它可以将组织血液中部分物质有选择性地进入脑组织
  20. 单位丢失员工档案赔偿问题

热门文章

  1. RabbitMQ 安装 rabbitmq_delayed_message_exchange插件
  2. Damp;G“辱华”争议广告女主发声:几乎断送了模特事业
  3. AIX PV VG LV详解
  4. Silverlight提示“Load 操作失败。远程服务器返回了错误: NotFound”
  5. MySQL更新死锁问题
  6. arcengine开发中遇到的错误汇总
  7. Dedecms文件夹目录解释完整版
  8. Java线程池在业务中的实践
  9. spring实现在一个类中调用另一个类的方法
  10. docker容器跨宿主机通信