设计模式系列之一:单例模式(Singleton Pattern)

原创 2015年11月19日 22:15:32

这一系列的文章我会从代码的思路上介绍目前编程中存在的编程模式,并且赋予这些代码的一些实例场景。

单例模式,即单实例模式,即在程序运行生命周期内。要么不存在一个类的实例(这里有些不严谨,理论上来说是否存在取决于代码设计和是否调用),要么只存在全局一个实例对象。

这样的例子在程序设计中有很多。对于某些特殊的类,在程序中只能new出一个实例,如果多个实例的话,暂且不说线程安全问题,从程序逻辑上面也会有很多问题。

比如我们只有一台打印机:
public class Printer{
        /**
         * Is Printer Running?
         * */
        private boolean isRunning;

        /**
         * Default Constructor
         * */
        public Printer(){

        }
        public void setRunning(boolean isRunning){
            this.isRunning = isRunning;
        }
    }

那么我们就不能在需要的时候都来创建一个新的实例,尤其是当一个实例有相应状态的时候(比如打印机在Isrunning = true的状态时候,此时该打印机是不能接受新任务的),所以此时情况我们需要创建一个全局唯一的实例来帮助我们完成程序逻辑。

  • 外界不能随意创建实例->构造方法私有
  • 外界不能创建,所以类需要自己创建唯一实例->类中需要维护自身实例的静态变量
  • 外界可以获取创建的静态变量->用公开静态方法获取静态实例

基于以上三个原则,我们重新编写上面的代码:

/**
 * Created by youweixi on 15/11/19.
 */
public class Printer{
    /**
     * Is Printer Running?
     * */
    private boolean isRunning;
    /**
     * Static Self
     * */
    private static Printer printer;

    /**
     * Default Constructor
     * */
    private Printer(){

    }

    /**
     * Public GetInstance
     * */
    public static Printer getInstance(){
        if (printer == null){
            printer = new Printer();
        }
        return printer;
    }

    public void setRunning(boolean isRunning){
        this.isRunning = isRunning;
    }
}

这样我们在程序中就不能通过new来创建Printer对象。只能通过getInstance方法来获取静态唯一实例。

但是上面的代码是存在问题的。

我们知道,程序在CPU上面是相互争夺时间片来运行的,即多个异步过程(进程、线程)之间的代码运行顺序是不确定的。

如果有两个代码片段同时需要调用getInstance来获取实例:

  1. 此时第一个线程发现printer == null是成立的,时间片耗尽,CPU转向另一个线程。
  2. 另一个线程也进入函数,判断printer == null仍然成立,分配实例,然后继续运行接下来代码。
  3. 此时时间片耗尽,CPU转向第一个线程,线程重新分配了一个新的实例造成多实例覆盖情况。

我们可以看到上面的单例模式在多线程中会发生问题,原因在于调用的方法和单例创建的时间。基于这两个原因,我们可以对上面的单例模式进行改进。

1. 提前单例创建时间

public class Printer{
    /**
     * Is Printer Running?
     * */
    private boolean isRunning;
    /**
     * Static Self
     * */
    private static Printer printer = new Printer();

    /**
     * Default Constructor
     * */
    private Printer(){

    }

    /**
     * Public GetInstance
     * */
    public static Printer getInstance(){
        return printer;
    }
}

即在编译时候创建静态变量,这样的话,在调用getInstance方法的时候不必再进行检测创建。这样的话可能会带来资源浪费,尤其是在很长一段时间内没有发生实例获取的项目中。

2. 对getInstance加同步控制synchronized

/**
     * Public GetInstance
     * */
    public static synchronized Printer getInstance(){
        if (printer == null){
            printer = new Printer();
        }
        return printer;
    }

这样的话可以保证每次只有一个线程拿到方法锁进入方法。但是这种方式会带来性能损失。如果工程中频繁通过调用getInstance获取实例而出现等待方法锁。

3. 二次检测
所谓的二次检测即是对方法二的改进,进行第一次检测的时候过滤大部分请求已经存在静态实例的请求,第二次检测才真正进行同步块中的静态实例分配。可以说这种方法是最安全和节省资源的。

/**
     * Public GetInstance
     * */
    public static Printer getInstance(){
        if (printer == null){
            synchronized (this){
                if (printer == null){
                    printer = new Printer();
                }
            }
        }
        return printer;
    }

这样的话即时有两个程序同时进入printer==null的程序逻辑也还是会只有一个会拿到内层检测创建的同步锁完成第一次创建。

版权声明:本文为本人原创,未经同意谢绝转载。

相关文章推荐

设计模式系列(八)单例模式(Singleton Pattern)

设计模式系列(八)单例模式(Singleton Pattern)     单例模式就是确保一个类只有一个实例,并提供一个全局的访问点。具体来看,就是指定义的某个类,在程序运行期间,只允许有一个实例...

设计模式-单例模式(singleton pattern)

单例模式定义:确保一个类只有一个实例,并提供全局访问点.    应用场景:书中介绍有  线程池  缓存  对话框  注册表 日志 打印机驱动程序的对象等   个人在android开发中 使用到的场景是...

Java设计模式之单例模式(Singleton Pattern)

Singleton Pattern单例模式:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类为单例类,它提供全局访问的方法.单例类是一种对象创建型模式.这是官方的说法,但看着还是...

【一】设计模式——单例模式(Singleton Pattern)

设计模式——单例模式 简单快捷的了解设计模式

C++设计模式之Singleton pattern(单例模式)

Singleton Pattern (单例模式) ---选自百度百科 单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例...

设计模式(一):单例模式(Singleton Pattern)

单例模式(Singleton Pattern)是设计模式中常用的一种,知识点包括:1、理解什么是单例模式、单例模式有什么优点/缺点、单例模式的应用场景;2、再来看看Java单例模式的6种代码实现方式、...
  • tjiyu
  • tjiyu
  • 2017-08-02 11:52
  • 445

Net设计模式实例之单例模式( Singleton Pattern)

一、单例模式简介(Brief Introduction)单例模式(Singleton Pattern),保证一个类只有一个实例,并提供一个访问它的全局访问点。单例模式因为Singleton封装它的唯一...

Python实现设计模式--01.单例模式(Singleton Pattern)

1、基于模块引用(饱汉模式) 建立文件Emperor_Singleton.py,内容如下: # 皇帝类 class Emperor(object): def say(self): ...

设计模式--单例模式【Singleton Pattern】

这个模式是很有意思,而且比较简单,但是我还是要说因为它使用的是如此的广泛,如此的有人缘,单例就是单一、独苗的意思,那什么是独一份呢?你的思维是独一份,除此之外还有什么不能山寨的呢?我们举个比较难复制的...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)