美文网首页
单例模式

单例模式

作者: 未扬帆的小船 | 来源:发表于2018-03-13 10:27 被阅读0次

单例模式有好几种写法,作为使用相对最为频繁的模式来说,新手应该会经常碰见!

单例模式的主要特征以及关键点:

  1. 构造函数不对外开放,一般为private;

  2. 通过一个静态方法或者枚举返回单例类对象;

  3. 确定单例类有且只有一个,特别是在多线程环境下;

  4. 确保单例类对象在反序列化的时候不会重新构建对象;

单例类会暴露一个公有的静态方法,直接调用该方法进行实例化(唯一对象实例),获取这个单例对象的过程中要确保线程安全,在多线程的情况下尤为重点,必须保证多线程环境下构造的单例类的对象有且只有一个。

说白了就是!!!!保证实例对象有且只有一个!

基础的写法有

一.饿汉模式

public class Demo{  
private static Demo mDemo;  
private Demo(){};  
public static synchroized Demo getInstance(){  
if(instance == null){  
instance = new Singleton();  
}  
return instance;  
}  
} 

eg:这个写法有个问题,因为使用了synchroized致使性能下降不少,即使第一次已经对该对象进行实例了,可是每次调用getInstance()的时候还是会进行同步,消耗不必要的资源。

总结:

优点:在使用的时候才进行实例,算是节约资源。

缺点:1 第一次加载的时候需要及时进行实例化,反映稍微有点慢。2.每次调用该方法都进行同步,造成不必要的资源开销。

所以,一般这个不考虑使用!

二. Double Check Lock (DCL)模式

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

eg:这里有个特点,就是两次判断对象是否为空。第一层是为了不必要的同步,第二层是判断在空的情况下创建实例。

大家对于第二层的意思可能不清楚,看下面分析:

首先,mDemo = new Demo();这句代码不是一个原子操作,编译器会将其编译成多条汇编指令,大致一下三步骤:

  1. 给Demo的实例分配内存。

  2. 调用Demo()的构造函数,初始化成员字段。

  3. 将mDemo对象指向分配的内存空间。(这时候,mDemo就不是null了)

问题主要就是因为在java编译器允许处理器乱序执行,已经JDK1.5之前JMM(java Memory Model )中的Cahce,寄存器到主内存会回顺序的规定,上面的2 3 是顺序是没办法保证的,有可能是123 或者132顺序,如果是后者,那可能在多线程的情况下会出现一个很大的问题,设想一下,线程A执行到3然后还没有执行2 就切换到线程B,此时mDemo已经不是空的,但是它实际上并没有实例化构造函数已经成员字段等,相等于内存空间中还只是空的情况,所以当线程B取走mDemo的时候,再使用就出错了!这个就是DCL失效问题。不过在1.5后已经修改了对volatile的具体化,只要在 private static volatile Demo mDemo = null,则可以保证mDemo对象每次都在主内存中读取,就可以使用DCL的写法来完成单例模式。

总结:

优点:资源利用率高,第一次执行才实例化对象,效率高。

缺点:第一次加载慢,偶尔因为java内存模式会失效,在高并发条件下有一点的缺陷。虽然发生的概率很小。

这个模式是单例模式使用是最多的!(除了低于1.6JDK版本 或者 并发环境很高的 时候另外一说)

三 静态内部类单例模式

public class Demo{  
private Demo(){ }  
public static Demo getInstance(){  
return DemoHolder.mDemo;  
}  
//静态内部类  
private static class DemoHolder{  
    private state final Demo mDemo = new Demo();  
}  
}  

eg:第一次加载Demo类的时候,并不会实例化它,只有在getInstance()的时候才会加载它,当第一次调用的时候会致使虚拟机加载DemoHolder类,这种方式不止可以确保线程安全,也可以确保单例对象的唯一性。同时也延迟了单例的实例化。

总结:优点:直接交由java虚拟机保证线程问题。并且在第一次调用后才实例节约资源。

缺点:加载需要时间,可能第一次也会偏慢点。

这个是最为推荐的单例模式实现方式!!!

以上是相对比较普遍的三种实现方法,相对而言。第三种方式是最为可取的,第二种除了两种特殊情况,也是可以选择的,第一种的缺点过于明显,在开发中最好做到不使用为妙。

四 当项目使用的单例模式比较多的时候,也可以使用一个容器将其存储起来,一是便于管理,二是可以对用户隐藏具体实现,降低一定的耦合性。

代码如下:

public class SingletonManager{  
private static Map<String,Object>objectMap = new HashMap<String,Object>;  
private SingletonManager(){};  
public static void registerService(String key, Object instance){  
    if(!objectMap.containsKey(key)){  
        objectMap.put(key,instance);  
        }}  
public static Object getService(String key){  
    return objectMap.get(key);  
    }   
}  

以上文章是看书籍总结的而来,原创作品,转载请注明出处!

相关文章

  • 【设计模式】单例模式

    单例模式 常用单例模式: 懒汉单例模式: 静态内部类单例模式: Android Application 中使用单例模式:

  • Android设计模式总结

    单例模式:饿汉单例模式://饿汉单例模式 懒汉单例模式: Double CheckLock(DCL)实现单例 Bu...

  • 2018-04-08php实战设计模式

    一、单例模式 单例模式是最经典的设计模式之一,到底什么是单例?单例模式适用场景是什么?单例模式如何设计?php中单...

  • 设计模式之单例模式详解

    设计模式之单例模式详解 单例模式写法大全,也许有你不知道的写法 导航 引言 什么是单例? 单例模式作用 单例模式的...

  • Telegram开源项目之单例模式

    NotificationCenter的单例模式 NotificationCenter的单例模式分析 这种单例模式是...

  • 单例模式Java篇

    单例设计模式- 饿汉式 单例设计模式 - 懒汉式 单例设计模式 - 懒汉式 - 多线程并发 单例设计模式 - 懒汉...

  • IOS单例模式的底层原理

    单例介绍 本文源码下载地址 1.什么是单例 说到单例首先要提到单例模式,因为单例模式是单例存在的目的 单例模式是一...

  • 单例

    iOS单例模式iOS之单例模式初探iOS单例详解

  • 单例模式

    单例模式1 单例模式2

  • java的单例模式

    饿汉单例模式 懒汉单例模式

网友评论

      本文标题:单例模式

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