美文网首页编程学习程序员移动开发
你真的会用单例模式吗?

你真的会用单例模式吗?

作者: 唠嗑008 | 来源:发表于2017-01-13 23:16 被阅读918次

一、简介:

 我们经常有这样的需求:  某一些类应该只存在一个实例  的时候,我们就可以用单例模式来应对.

单例模式:确保一个类只有一个实例,并提供一个全局访问点.

单例模式是所有设计模式中最简单的一个,也是大部分人最早知道的一个设计模式.

二、我们经常用的2种单例模式(懒汉式、饿汉式)

(1)饿汉式:

饿汉式单例类.在类初始化时,已经自行实例化

public class Singleton {  
    private Singleton() {}  
    private static Singleton singleton = new Singleton();  
    public static Singleton getInstance() {  
        return singleton ;  
    }  
}  

饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以是线程安全的。

(2)懒汉式

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

备注


Paste_Image.png
 单例模式的懒汉式实现方式体现了延迟加载的思想,什么是延迟加
载呢?  通俗点说,就是一开始不要加载
资源或者数据,一直等,等到马上就要使用这个资源或者数据了,躲不过去了才加载,所以也称
Lazy Load,不是懒惰啊,是“延迟加载”,这在实际开发中是一种很常见的思想,尽可能的节约资源。
   单例模式的懒汉式实现还体现了缓存的思想,缓存也是实际开发中非常常见的功能。简单讲就是,如果
某些资源或者数据会被频繁的使用,而这些资源或数据存储在系统外部,比如数据库、硬盘文件等,
那么每次操作这些数据的时候都从数据库或者硬盘上去获取,速度会很慢,会造成性能问题。 一个简单的
解决方法就是:把这些数据缓存到内存里面,每次操作的时候,先到内存里面找,看有没有这些数据,
如果有,那么就直接使用,如果没有那么就获取它,并设置到缓存中,下一次访问的时候就可以直接从内存
中获取了。从而节省大量的时间,当然,缓存是一种典型的空间换时间的方案。

两种单例模式的比较

比较上面两种写法:
1、懒汉式是典型的时间换空间,也就是每次获取实例都会进行判断,看是否需要创建实例,费判断的时间,当然,如果一直没有人使用的话,那就不会创建实例,节约内存空间。
2、 饿汉式是典型的空间换时间,当类装载的时候就会创建类实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断了,节省了运行时间。

(3)双重检查加锁

public class Singleton {        

        private volatile static Singleton instance = null;
        private Singleton() {}
        public static Singleton getInstance() {
            //先检查实例是否存在,如果不存在才进入下面的同步块
            if (instance == null) {
                //同步块,线程安全的创建实例
                synchronized (Singleton.class) {
                    //再次检查实例是否存在,如果不存在才真的创建实例
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }

双重检查详解
可以使用“双重检查加锁”的方式来实现,就可以既实现线程安全,又能够使性能不受到大的影响。
那么什么是“双重检查加锁”机制呢? 所谓双重检查加锁机制,指的是:并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法过后,先检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查。进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。 双重检查加锁机制的实现会使用一个关键字volatile,它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。 这种实现方式既可使实现线程安全的创建实例,又不会对性能造成太大的影响,它只是在第一次创建实例的时候同步,以后就不需要同步了,从而加快运行速度。 注意:在Java1.4及以前版本中,很多JVM对于volatile关键字的实现有问题,会导致双重检查加锁的失败,因此双重检查加锁的机制只能用在Java5及以上的版本。

(4)、静态内部类单例模式

public class Singleton {

        private static class Holder{
            private static Singleton INSTANCE = new Singleton();
        }
        public static Singleton getInstance(){
            return Holder.INSTANCE;
        }
    }

当第一次加载Singleton类时并不会初始化INSTANCE,只有在第一次调用getInstance方法时才会导致INSTANCE被初始化。这种方式不仅能够保证线程安全,也能保证单例对象的唯一性,同时也延长了单例的实例化。

小结

1、双重检查非常适用于高并发,我们熟知的开源库Eventbus,ImageLoader等都是用的双重检查锁方式实现单例

2、单例模式是运用频率很高的模式,但是,由于在客户端通常没有高并发的情况,因此,选择哪种实现方式都不会有太大的影响。即使如此,出于效率考虑,推荐使用DCL单例(双重检查锁定)和静态内部类单例模式。

相关文章

  • 你真的会用单例模式吗

    转载请注明出处:http://tedyin.me/2016/03/13/singlton-pattern/ 今天给...

  • 你真的会用单例模式吗?

    一、简介: 单例模式:确保一个类只有一个实例,并提供一个全局访问点. 单例模式是所有设计模式中最简单的一个,也是大...

  • 单例模式(Java内部类加载顺序)

    你真的会写单例模式吗——Java实现Android设计模式源码解析之单例模式深度分析 Java 的枚举类型:枚举的...

  • 你真的会写单例吗?

    你真的会写单例吗? 摘录来源 单例的正确姿势 Java单例模式可能是最简单也是最常用的设计模式,一个完美的单例需要...

  • 单例模式的优化方案

    参考:你真的会写单例吗? 单例模式最常见的就是懒汉式加载: 例: 当调用getInstance方法时才去创建对象,...

  • Java单例模式

    转载: 你真的会写单例模式吗-------Java实现 单例模式可能是代码最少的模式了,但是少不一定意味着简单,想...

  • 简记Android源码设计模式——第一篇

    单例模式 介绍 单例模式可谓是都会用到的一个设计模式。单例顾名思义只有一个实例。就像规定任何时候你只能有一个老婆或...

  • 单例模式

    在我们的开发中,有很多地方会用到单例模式,那么会写基本的单例模式使我们基本的素养,如果说现在不会手写单例模式的,那...

  • 羊皮书APP(Android版)开发系列(二十二)10分钟秒懂单

    单例模式在实际开发过程中经常会用到,我们有必要充分的理解单例模式。单例模式有多种写法,分为懒汉式、饿汉式、双重锁等...

  • Go单例模式

    单例模式回顾 以前在做java的时候,经常会用到设计模式,如单例模式、工厂模式、观察者模式等。其实设计模式和语言无...

网友评论

  • aad089bfd751:枚举单例呢?
  • 竿牍:看标题,我以为是说单例模式在哪些场景下使用。

    文章内容只是告诉说写法,
  • c072c1d1f253:满详细的,开始看代码的时候发现好像有点问题感觉像只写了一半的样子,后来发现那个图片可以左右移动,哈哈。点赞
    唠嗑008: @小胡的Singer 有些东西吧,不用非要扣细枝末节,能获取到对自己有用的关键部分就好,互相学习
  • 冰鉴IT:字写错了,说实话有点误人子弟
  • Wilstro:饿汉式的代码没对吧
  • 大数据小白白:误人子弟
  • wxyjj:前面我都想着要不要写一篇单例模式,现在看到你这篇挺不错的,加油。😀
    唠嗑008: @locality 互相学习!
  • 为什么一定要起昵称:所以应该怎么用?
    唠嗑008: @为什么一定要起昵称 谢谢!
    为什么一定要起昵称:@陪你唠嗑 http://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html看看这里的单例模式
    唠嗑008:@为什么一定要起昵称 个人比较喜欢后2种!
  • 6b5e74981e77:非常详细,:+1:🏻
    唠嗑008:@zhy_nju 互相学习,共同进步!

本文标题:你真的会用单例模式吗?

本文链接:https://www.haomeiwen.com/subject/wvasbttx.html