美文网首页
设计模式-单例

设计模式-单例

作者: EvilsoulM | 来源:发表于2015-11-22 16:09 被阅读77次

单例模式

单例设计模式是设计模式中使用最普遍的模式之一。用于产生一个对象的具体实例,它可以确保系统中一个类只产生一个实例。

单例带来的好处

1.对于频繁创建的对象,可以省略创建对象所花费的时间,这对于一些重量级的对象而言,是非常可观的一笔开销。
2.由于new操作的次数减少,因而对于系统内存的使用频率也会降低,这也将减轻GC压力,缩短GC停顿时间。

单例的实现

单例模式的核心在于通过一个接口返回唯一对象的实例,最简单的例子:

public class SimpleSingleInstance {
    private SimpleSingleInstance() { 
     System.out.println("SimpleSingleInstance");    
    }    
    private static SimpleSingleInstance instance = new SimpleSingleInstance();    
    public static SimpleSingleInstance getInstance() {
        return instance;
    }
}

这个例子实现方式非常简单,而且十分可靠。
1.一个private 访问级别的构造函数,确保单例不会再系统中被实例化
2.getInstance保证只能获取到一个唯一的单例对象

但是这个类有个很明显的缺点,没有做到延迟加载,也就是说在jvm加载单例类的时候,单例对象就会被创建。

public class SimpleSingleInstance {
    private SimpleSingleInstance() { 
     System.out.println("SimpleSingleInstance");    
    }    
    private static SimpleSingleInstance instance = new SimpleSingleInstance();    
    public static SimpleSingleInstance getInstance() {
        return instance;
    }
}
  public static void log(){
      System.out.println("log");
  }

当我们调用SimpleSingleInstance.log();的时候程序输出:

SimpleSingleInstance
log

虽然我们没有使用单例类,但是还是被创建出来了,如果这个单例创建比较耗时的话我们在调用他的静态方法的时候,也就造成了该方法第一次的执行时间加长,为了解决这种问题我们引入了赖加载。

public class LazySingleInstance {
    private LazySingleInstance() {
        System.out.println("LazySingleInstance");
    }    private static LazySingleInstance instance = null;
    public  synchronized static LazySingleInstance getInstance() {
                if (instance == null) {
                    instance = new LazySingleInstance();
                }
        return instance;
    }
}

首先将instance初始值为null,确保系统启动的时候不会加载,其次在getIntance判断instance是不是为null不为null采取创建对象,当然也加上了同步锁保障多线程同时访问不会创建出多个对象,也就违反了我们写单例的目的。

使用上面的例子虽然实现了延迟加载,但是也加入的同步锁,再多线程中,它的耗时也会大大增加。

for (int i = 0; i < 5; i++) {
    new Thread() {
        @Override
        public void run() {
            for (int i = 0; i < 100000; i++) {
                long beginTime = System.currentTimeMillis();
                SimpleSingleInstance.getInstance(); 
                  spendTime += (System.currentTimeMillis() - beginTime);
                if (i == 100000 - 1) { 
                   System.out.println("SimpleSingleInstance spend:" + (spendTime));
                }
            }
        }
    }.start();
}

我们开启五个线程去执行SimpleSingleInstance耗时

SimpleSingleInstance
SimpleSingleInstance spend:19
SimpleSingleInstance spend:17
SimpleSingleInstance spend:17
SimpleSingleInstance spend:19
SimpleSingleInstance spend:20

我们开启五个线程去执行SimpleSingleInstance耗时

LazySingleInstance
LazySingleInstance spend:268
LazySingleInstance spend:268
LazySingleInstance spend:273
LazySingleInstance spend:274
LazySingleInstance spend:274

开启五个线程同时执行,可以看出性能相差巨大。

为了解决这个问题,我们对LazySingleInstance进行改造

public class LazySingleInctanceV2 {
    private LazySingleInctanceV2() {
        System.out.println("LazySingleInctanceV2");
    }
    private volatile static LazySingleInctanceV2 instance = null;
    public static LazySingleInctanceV2 getInstance() {//去掉这里同步锁,在大部分情况下instance都不为null
        if (instance == null) {
            synchronized (LazySingleInctanceV2.class) {
                if (instance == null) {//双重判断避免构建多个对象
                    instance = new LazySingleInctanceV2();
                }
            }
        }
        return instance;
    }
}
LazySingleInctanceV2
LazySingleInctanceV2 spend:28
LazySingleInctanceV2 spend:29
LazySingleInctanceV2 spend:29
LazySingleInctanceV2 spend:29
LazySingleInctanceV2 spend:29

可以看出运行时间基本上和SimpleSingleInstance保持在了一个数量级

当然还有一种更加简单的实现方式

public class StaticSingleInstance {
    private StaticSingleInstance() {
        System.out.println("StaticSingleInstance");
    }
    public static StaticSingleInstance getInstance() {
        return SingleInstanceHolder.instance;
    }
    private static class SingleInstanceHolder {//内部类来维护单例的实例
        private static StaticSingleInstance instance = new StaticSingleInstance();
    }
}

在上面的实现中,使用内部类来维护单例的实例,当单例被加载的时候,其内部类并不会被初始化,当StaticSingleInstance类被加载入JVM的时候,不会初始化单例类,而当调用getInstance的时候才回去加载SingleInstanceHolder从而初始化instance。

StaticSingleInstance
StaticSingleInstance spend:22
StaticSingleInstance spend:23
StaticSingleInstance spend:23
StaticSingleInstance spend:23
StaticSingleInstance spend:24

相关文章

  • 单例模式Java篇

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

  • python中OOP的单例

    目录 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计模式 是 前人...

  • 单例

    目标 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计模式 是 前人...

  • python 单例

    仅用学习参考 目标 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计...

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

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

  • 设计模式第二篇、单例设计模式

    目录1、什么是单例设计模式2、单例设计模式的简单实现3、单例设计模式面临的两个问题及其完整实现4、单例设计模式的应...

  • 设计模式 - 单例模式

    设计模式 - 单例模式 什么是单例模式 单例模式属于创建型模式,是设计模式中比较简单的模式。在单例模式中,单一的类...

  • 2、创建型设计模式-单例设计模式

    江湖传言里的设计模式-单例设计模式 简介:什么是单例设计模式和应用 备注:面试重点考查 单例设计模式:这个是最简单...

  • 设计模式之单例模式

    单例设计模式全解析 在学习设计模式时,单例设计模式应该是学习的第一个设计模式,单例设计模式也是“公认”最简单的设计...

  • 设计模式

    常用的设计模式有,单例设计模式、观察者设计模式、工厂设计模式、装饰设计模式、代理设计模式,模板设计模式等等。 单例...

网友评论

      本文标题:设计模式-单例

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