单利模式的应用场景:

  单利模式(Singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例。并提供一个全局反访问点。单利模式是创建型模式。单利模式在生活中应用也很广泛,比如公司CEO只有一个,部门经理只有一个等。JAVA中ServletCOntext,ServetContextCOnfig等,还有spring中ApplicationContext应用上下文对象,SessionFactory,数据库连接池对象等。使用单利模式可以将其常驻于内存,可以节约更多资源。

写法:

  1:懒汉模式(线程不安全)

  1. /**
  2. * 线程不安全的懒汉式单利模式
  3. *
  4. * Created by gan on 2019/11/17 17:33.
  5. */
  6. public class LazySingleton {
  7. private static LazySingleton instance;
  8.  
  9. //构造方法私有化
  10. private LazySingleton() {
  11. }
  12.  
  13. public static LazySingleton getInstance() {
  14. if (instance != null) {
  15. instance = new LazySingleton();
  16. }
  17. return instance;
  18. }
  19. }

  上面的代码,提供一个静态对象instance,构造函数私有化防止外部创建对象,提供一个静态的getInstance方法来给访问者一个单利对象。这种写法的缺点就是没有考虑到线程安全问题,当多个访问者同时访问的时候很有可能创建多个对象。之所以叫懒汉式,是因为这种写法是使用的时候才创建,起到了懒加载Lazy loading的作用,实际开发中不建议采用这种写法。

  2:线程安全的懒汉式(加锁)

  1. /**
  2. * 线程安全的懒汉式单利模式
  3. *
  4. * Created by gan on 2019/11/17 17:33.
  5. */
  6. public class LazySingleton {
  7. private static LazySingleton instance;
  8.  
  9. //构造方法私有化
  10. private LazySingleton() {
  11. }
  12.  
  13. public synchronized static LazySingleton getInstance() {
  14. if (instance != null) {
  15. instance = new LazySingleton();
  16. }
  17. return instance;
  18. }
  19. }

  这种写法就是在第一种的基础上添加了synchronized关键字保证了线程安全。这种写法在并发高的时候虽然保证了线程安全,但是效率很低,高并发的时候所有访问的线程都要排队等待,所以实际开发中也不建议采用。

  3:恶汉式(线程安全)

  1. /**
  2. * 饿汉式(线程安全)
  3. * Created by gan on 2019/10/28 22:52.
  4. */
  5. public class HungrySigleton {
  6.  
  7. public static final HungrySigleton instance = new HungrySigleton();
  8.  
  9. private HungrySigleton(){}
  10.  
  11. public static HungrySigleton getInstance(){
  12. return instance;
  13. }
  14. }

  直接在运行(加载)这个类的时候创建了对象,之后直接访问。显然这种方式没有起到Lazy loading的效果。但是是线程安全的,实际开发中还是比较常用。

  4:静态内部类(线程安全)

  1. /**
  2. * 静态内部类方式
  3. * Created by gan on 2019/11/17 17:46.
  4. */
  5. public class StaticInnerClassSingleton {
  6.  
  7. //构造方法私有化
  8. private StaticInnerClassSingleton() {}
  9.  
  10. //内部类
  11. private static class HolderInnerClass {
  12. //需要提供单利对象的外部类作为静态属性加载的时候就初始化
  13. private static StaticInnerClassSingleton instance = new StaticInnerClassSingleton();
  14. }
  15.  
  16. //对外暴漏访问点
  17. public static StaticInnerClassSingleton getInstance() {
  18. return HolderInnerClass.instance;
  19. }
  20. }

  这种内部类跟饿汉式单利有很多相似的地方,相比饿汉式单利模式的区别也是好处在于:静态内部类不在单利类加载时就加载,而是在调用getInstance()方法的时候才进行加载,达到了类似于懒汉式的效果,而且这种方法又是线程安全的。实际开发中也建议采用。

  5:枚举方法单利(线程安全)

  1. /**
  2. * 枚举单利模式
  3. * Created by gan on 2019/11/17 17:57.
  4. */
  5. public enum EnumSingleton {
  6. INSTANCE;
  7.  
  8. public void otherMetthod() {
  9. System.out.println("需要单利对象调用的方法。。。");
  10. }
  11. }

  Effective Java作者Josh Bloch提倡的方式,好处有如下:

  1:自由串行化。

  2:保证了一个实例

  3:线程安全

  这种方式防止了单利模式被破坏,而且简洁写法简单,而且绝对的线程安全,但是有个缺点就是不能继承。

  6:双重检查法(通常线程安全,低概率不安全)

  1. /**
  2. * Double check
  3. * Created by gan on 2019/11/17 18:03.
  4. */
  5. public class DoubleCheckSingleton {
  6. private static DoubleCheckSingleton instance;
  7.  
  8. private DoubleCheckSingleton() {}
  9.  
  10. public static DoubleCheckSingleton getInstance() {
  11. if (instance == null) {
  12. synchronized (DoubleCheckSingleton.class) {
  13. if (instance == null) {
  14. instance = new DoubleCheckSingleton();
  15. }
  16. }
  17. }
  18. return instance;
  19. }
  20. }

  上面的这种写法在并发极高的时候也可能会出现问题(当然这种概率非常小,但是毕竟还是有的嘛),解决的方案就是给instance的声明加上volatile关键字即可。于是就出现了下面第7总写法。

  7:Double check(volatile)

  1. /**
  2. * Double check volatile
  3. * Created by gan on 2019/11/17 18:03.
  4. */
  5. public class DoubleCheckSingleton {
  6. private volatile static DoubleCheckSingleton instance;
  7.  
  8. private DoubleCheckSingleton() {}
  9.  
  10. public static DoubleCheckSingleton getInstance() {
  11. if (instance == null) {
  12. synchronized (DoubleCheckSingleton.class) {
  13. if (instance == null) {
  14. instance = new DoubleCheckSingleton();
  15. }
  16. }
  17. }
  18. return instance;
  19. }
  20. }

volatile关键字的其中一个作用就是禁止指令重排序,把instance声明volatile后,对它的操作就会有一个内存屏障(什么是内存屏障?),这样在赋值完成之前,就不会调用读操作。这里具体的原因网上也是众说纷纭,这里不进行具体阐述。

  8:ThreadLocal实现单利模式(线程安全)

  1. /**
  2. * ThreadLocal实现单利模式
  3. * Created by gan on 2019/11/17 18:17.
  4. */
  5. public class ThreadLocalSingleton {
  6.  
  7. private static final ThreadLocal<ThreadLocalSingleton> threadLocal = new ThreadLocal() {
  8. @Override
  9. protected ThreadLocalSingleton initialValue() {
  10. return new ThreadLocalSingleton();
  11. }
  12. };
  13.  
  14. private ThreadLocalSingleton(){}
  15.  
  16. public static ThreadLocalSingleton getInstance(){
  17. return threadLocal.get();
  18. }
  19. }

  ThreadLocal会为每个线程提供一个独立的变量副本,从而隔离了多个线程堆数据的访问冲突。对于多线程资源共享问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal则采用了“以空间换时间”的方式(主要就是避免了加锁排队)。 前者提供一份变量,让不同的线程排队访问,而后者为每一个线程提供了一份变量,因此可以同时访问而互不影响。但是实际是创建了多个单利对象的。

单利模式的破坏:

  1:序列化破坏

    一个对象创建好以后,有时候需要将对象序列化然后写入磁盘。下次在从磁盘中读取并反序列化,将其转化为内存对象。反序列化后的对象会重新分配内存,即创建型的对象。这样就违背了单利模式的初衷。解决这种方式的方法就是在单利类中新增一个 private Object readResolve();方法即可,具体原因可以看看序列化和反序列化的源码。

  2:反射

    通过反射“暴力破解”也能破坏单利模式,具体暂时不阐述。

  3:克隆

    克隆也会破坏单利模式,具体暂时不阐述。

代码链接:https://gitee.com/ganganbobo/gps-parent

Java设计模式之单利模式(Singleton)的更多相关文章

  1. Java 设计模式之单利模式

    一.首先介绍一下单例模式:     单例模式(Singleton),也叫单子模式,是一种常用的软件设计模式.在应用这个模式时,单例对象的类必须保证只有一个实例存在.许多时候整个系统只需要拥有一个的全局 ...

  2. java 设计模式之单利模式以及代理模式(静态)

    1:单利模式: public class Singleton { private static Singleton uniqueInstance = null; private Singleton() ...

  3. java设计模式3--单例模式(Singleton)

    本文地址:http://www.cnblogs.com/archimedes/p/java-singleton-pattern.html,转载请注明源地址. 单例模式 保证一个类仅有一个实例,并提供一 ...

  4. Java设计模式之工厂模式(Factory模式)介绍(转载)

    原文见:http://www.jb51.net/article/62068.htm 这篇文章主要介绍了Java设计模式之工厂模式(Factory模式)介绍,本文讲解了为何使用工厂模式.工厂方法.抽象工 ...

  5. java设计模式6--适配器模式(Adapter )

    本文地址:http://www.cnblogs.com/archimedes/p/java-adapter-pattern.html,转载请注明源地址. 适配器模式(别名:包装器) 将一个类的接口转换 ...

  6. java设计模式5--原型模式(Prototype)

    本文地址:http://www.cnblogs.com/archimedes/p/java-prototype-pattern.html,转载请注明源地址. 原型模式 用原型实例指定创建对象的种类,并 ...

  7. Java设计模式——装饰者模式

    JAVA 设计模式 装饰者模式 用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式 ...

  8. 浅析JAVA设计模式之工厂模式(一)

    1 工厂模式简单介绍 工厂模式的定义:简单地说,用来实例化对象,取代new操作. 工厂模式专门负责将大量有共同接口的类实例化.工作模式能够动态决定将哪一个类实例化.不用先知道每次要实例化哪一个类. 工 ...

  9. JAVA设计模式--装饰器模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰 ...

随机推荐

  1. js中submit和button的区别

    今天写一个js验证 遇到点小坑 记录一下 button-普通按钮,submit-提交按钮. submit是button的一个特例,也是button的一种,它把提交这个动作自动集成了,submit和bu ...

  2. php 学习编译扩展

    原文 : http://kimi.it/496.html 系统环境 : Ubuntu 目标 : 可以像 php 提供的内部函数一样,使用 myecho 函数 : 输出如下 : 1. 获取 php 的源 ...

  3. Hello World ! 节日快乐!

    节日快乐! 世界你好,Hello World Java public class HelloWorld{ public static void main(String[] args) { System ...

  4. Windows突破远程连接最大数去掉限制登录

    当对方设置最大连接数 超过限制时 可以用这个命令 win+r  输入 mstsc /v:192.168.18.131:3389 /console   windows server 2003 sp2 以 ...

  5. 1.Linux-CentOS7.6安装教程

    了解Linux Linux 就是一个操作系统,主要为企业提供支持与服务. 学习Linux需要具备什么基础?能看懂中文,能看懂简单的 English ​ 1.什么是Linux? Linux:和我们常见的 ...

  6. JavaScript ES6函数式编程(三):函子

    前面二篇学习了函数式编程的基本概念和常见用法.今天,我们来学习函数式编程的最后一个概念--函子(Functor). 相信有一部分同学对这个概念很陌生,毕竟现在已经有很多成熟的轮子,基本能满足我们日常的 ...

  7. Rust入坑指南:千人千构

    坑越来越深了,在坑里的同学让我看到你们的双手! 前面我们聊过了Rust最基本的几种数据类型.不知道你还记不记得,如果不记得可以先复习一下.上一个坑挖好以后,有同学私信我说坑太深了,下来的时候差点崴了脚 ...

  8. Go中http超时问题的排查

    背景 排查 推测 连接超时 疑问 http2 解决超时 并发连接数 服务端限制 真相 重试 解决办法 问题1 背景 最新有同事反馈,服务间有调用超时的现象,在业务高峰期发生的概率和次数比较高.从日志中 ...

  9. POJO和JavaBean

    1.POJO POJO(Plain Ordinary Java Object):POJO就是一个简单的普通的Java对象,它不包含业务逻辑或持久逻辑等,但不是JavaBean.EntityBean等, ...

  10. LeetCode 1: single-number

    Given an array of integers, every element appears twice except for one. Find that single one. soluti ...