单例模式定义
它是一种常用的软件设计模式,其定义是单例对象的类只能允许一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为,他的作用是确保某个类只有一个实例,避免产生多个对象消耗过多的资源

为什么要用单例模式?
1、单例模式节省公共资源

比如:大家都要喝水,但是没必要每人家里都打一口井是吧,通常的做法是整个村里打一个井就够了,大家都从这个井里面打水喝。

对应到我们计算机里面,像日志管理、打印机、数据库连接池、应用配置。

2、单例模式方便控制

就像日志管理,如果多个人同时来写日志,你一笔我一笔那整个日志文件都乱七八糟,如果想要控制日志的正确性,那么必须要对关键的代码进行上锁,只能一个一个按照顺序来写,而单例模式只有一个人来向日志里写入信息方便控制,避免了这种多人干扰的问题出现。

单例模式优缺点
优点:系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。

缺点:可读性差,当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用 new,可能会给其他开发人员造成困扰,特别是看不到源码的时候。单例模式中在使用反射时,对象也可能不唯一,所以我们要注意不要认定单例模式唯一是其好处,从而生成刻板印象

适用场合

  • 需要频繁的进行创建和销毁的对象
  • 创建对象时耗时过多或耗费资源过多,但又经常用到的对象;
  • 工具类对象或者频繁访问数据库或文件的对象。

单例模式的实现步骤:

(1)将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。

(2)在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型。

(3)定义一个静态方法返回这个唯一对象。

注意事项:
单例模式在多线程的应用场合下必须小心使用。如果当唯一实例尚未创建时,有两个线程同时调用创建方法,那么它们同时没有检测到唯一实例的存在,从而同时各自创建了一个实例,这样就有两个实例被构造出来,从而违反了单例模式中实例唯一的原则。 解决这个问题的办法是为指示类是否已经实例化的变量提供一个互斥锁(虽然这样会降低效率)。

单例模式的实现方式有两种:1.饿汉模式 2.懒汉模式

1.饿汉模式

/*** 单例模式——饿汉模式*/
public class ThreadDemo14 {static class Singleton{//将构造函数设置为私有,因为单例对象的类只能允许一个实例存在private Singleton(){}//设置一个私有属性,其实就是它的实例private static Singleton instance = new Singleton();//提供统一的获取实例的方法public static Singleton getSingleton(){return instance;}}public static void main(String[] args) {Singleton singleton1 = Singleton.getSingleton();Singleton singleton2 = Singleton.getSingleton();//如果返回true说明是同一个实例,如果返回false,则说明有多个对象System.out.println(singleton1 == singleton2);}
}

代码分析:

饿汉式顾名思义,就是这个汉子很饿,一上来就把单例对象创建出来了,要用的时候直接返回即可,这种是单例模式中最简单的一种实现方式。但是问题也比较明显。单例在还没有使用到的时候,初始化就已经完成了。如果程序从头到位都没用使用这个单例的话,单例的对象还是会创建,这就造成了不必要的资源浪费。

2.懒汉模式(线程不安全)[不可用]

/*** 单例模式——懒汉模式*/
public class ThreadDemo15 {static class Singleton{//将构造函数设置为私有private Singleton(){}//设置一个私有属性,并且不会对它进行赋值private static Singleton instance = null;public static Singleton getInstance(){//对其进行判断,当为空的时候再去创建一个对象if(instance == null){instance = new Singleton();}return instance;}}public static void main(String[] args) {//切记不能使用Singleton singleton1 = new Singleton(),这样之后来调用getInstance方法,// 因为一旦new就会产生新的对象Singleton singleton1 = Singleton.getInstance();Singleton singleton2 = Singleton.getInstance();System.out.println(singleton1 == singleton2);}
}

优点:如果真实使用的情况下才会创建资源,如果没人调用就可以省略创建的对象的步骤了

注意:
这种写法起到了懒加载的效果,但只能在单线程下使用。如果在多线程下,一个线程进入了 if (instance == null) 判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式。

—————————————————————————————————————————

饿汉模式和懒汉模式的线程安全问题

(一个线程)单线程是不存在线程安全的
首先要知道影响线程安全的五个因素:
a)抢占式
b)多个线程修改同一个变量
c)内存可见性
d)原子性
e)编译器优化

而这里面我们从原子性的角度去分析
1.饿汉模式

2.懒汉模式

2.1.懒汉模式(线程安全,但是不推荐使用)

————————————————————————————
2.2.懒汉模式(同步代码块,线程安全,但是不可用)

但是这种同步并不能起到线程同步的作用。假如一个线程进入了 if (instance == null) 判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。

2.3.懒汉模式双重校验锁
双检索模式,进行了两次判断,第一次判断时为了避免不要的实例,第二次是为了进行线程同步,避免多线程问题。
由于 new Singleton()创建对象的时候jvm中可能会重新排序,在多线程下存在风险,使用volatile关键字可以当线程改变其值后通知其他线程改变并且不会被jvm重新排序,解决该问题。

static class Singleton{private Singleton(){}private static volatile Singleton instance = null;public static Singleton getInstance(){if(instance == null){synchronized (Singleton.class){//这里再加一层判断if(instance == null){instance = new Singleton();}}}return instance;}}

这种方式跟饿汉式方式都是采用了类装载的机制来保证初始化实例时只有一个线程,不同的地方在饿汉式方式是只要 Singleton 类被装载就会实例化,没有懒加载的作用,而静态内部类方式在 Singleton 类被装载时并不会立即实例化,而是在需要实例化时,调用 getInstance 方法,才会装SingletonInstance 类,从而完成 Singleton 的实例化。这种方法,避免了线程不安全,延迟加载,效率高。
类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM 帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。

【线程】——单例模式相关推荐

  1. p8大佬告诉你JSR - 133 都解决了哪些问题?

    究竟什么是内存模型? 在多处理系统中,每个 CPU 通常都包含一层或者多层内存缓存,这样设计的原因是为了加快数据访问速度(因为数据会更靠近处理器) 并且能够减少共享内存总线上的流量(因为可以满足许多内 ...

  2. 多线程编程指南 part 2

    多线程编程指南 Sun Microsystems, Inc. 4150 Network Circle Santa Clara, CA95054 U.S.A. 文件号码819–7051–10 2006 ...

  3. 用模板实现单例模式(线程安全)、模板方式实现动态创建对象

    一.用模板实现单例模式 在前面的文章中,用过多种方法实现单例模式,现在用模板方式来实现: 为了实现线程安全,需要在linux 下使用pthread_mutex_t 加锁,请使用g++ 编译并需要链接 ...

  4. C++ 单例模式析构函数的运用,析构函数的线程安全

    C++单例模式析构函数的应用 https://blog.csdn.net/realxie/article/details/7090493 C++实现线程安全的单例模式 https://www.cnbl ...

  5. Android之线程安全的单例模式,Adapter注意事项之引用传值

    线程安全的单例模式 单位模式一般写法如下: public static FestivalLab mInstance; private FestivalLab() { } public static F ...

  6. 如何看待Spring下单例模式与线程安全的矛盾

    前言 有多少人在使用Spring框架时,很多时候不知道或者忽视了多线程的问题?   因为写程序时,或做单元测试时,很难有机会碰到多线程的问题,因为没有那么容易模拟多线程测试的环境.那么当多个线程调用同 ...

  7. 线程的同步之Synchronized在单例模式中的应用

    synchronized在单例模式中的使用 在单例模式中有一种懒汉式的单例,就是类初始化的时候不创建对象.等第一次获取的时候再创建对象.这种单例在单线程下是没有问题的获取的也都是同一个对象.但是如果放 ...

  8. 实现线程安全的单例模式

    在某些应用环境下面,一个类只允许有一个实例,这就是著名的单例模式.单例模式分为懒汉模式,跟饿汉模式两种. 首先给出饿汉模式的实现 template <class T> class sing ...

  9. 单例模式和HttpContext线程内唯一

    单例模式 --> 多个用户会使用同一个EF,且这个EF一直不能释放,EF追踪的数据越来越多,服务器内存迟早爆炸 (联想应用程序池,用户可能会用到被人用过的Application,里面的EF也是被 ...

  10. std string与线程安全_这才是现代C++单例模式简单又安全的实现

    前言 说到单例模式,很多人可能都已经很熟悉了,这也是面试常问的一个问题.对于单线程而言,单例的实现非常简单,而要写出一个线程安全的单例模式,曾经有很多种写法.有兴趣的可以参考这篇文章<单例模式很 ...

最新文章

  1. python程序设计报告-20194115 实验二《Python程序设计》实验报告
  2. 用户名 不在 sudoers文件中,此事将被报告
  3. PHP学习方向-进阶(二)
  4. Windows 10 RedStone2值得期待的五大功能猜想
  5. matplotlib.patches.Polygon
  6. 二分法其实很简单,为什么老是写不对!!!
  7. Python字典对象实现原理
  8. 已知p是一个指向类a的数据成员m的指针_C++ this指针的理解和作用
  9. 批发网商品采集API接口
  10. 扩展欧几里得算法的讲解
  11. 三种数据结构总结(party_bid_core)
  12. 面试被虐题— 谨以此致,mark一个悲惨的下午
  13. 2022天梯赛 L1-086 斯德哥尔摩火车上的题
  14. 四川小学计算机的组成是几年级学,小学三年级计算机教案
  15. Linux虚拟机安装及Docker常用操作
  16. python return返回值格式化_day11__函数名的应用,python新特f-strings格式化输出、迭代器...
  17. 错误1053: 服务没有及时地响应启动或控制请求
  18. C语言实现简易三子棋,支持双人对战,电脑可拦截
  19. NSPredicate 模糊、精确、查询
  20. 关闭互斥句柄达到游戏多开MFC源码

热门文章

  1. C语言tolower函数介绍、示例和实现
  2. php图片滑动的属性,JavaScript_javascript图片滑动效果实现,本文为大家分享了javascript图片 - phpStudy...
  3. Spring Cloud与微服务学习总结(2)——Spring Cloud相较于Dubbo等RPC服务框架的优势
  4. Nginx学习总结(6)——Nginx + https + 免费SSL证书配置指南
  5. Java基础学习总结(53)——HTTPS 理论详解与实践
  6. Java基础学习总结(21)——常用正则表达式列表
  7. 自定义注解完成数据库切库
  8. 从零实现Vue的组件库(零)- 基本结构以及构建工具
  9. 百度的一道 java 高频面试题的多种解法
  10. 震后十年,他重走那条生死送货线