设计模式系列之一:单例模式(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)     单例模式就是确保一个类只有一个实例,并提供一个全局的访问点。具体来看,就是指定义的某个类,在程序运行期间,只允许有一个实例...

设计模式系列之01-单例模式(Singleton Pattern)

概述 Singleton模式要求一个类有且仅有一个实例,并且提供了一个全局的访问点。这就提出了一个问题:如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?客户程序在调用某一个类时,它是...

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

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

深入浅出设计模式-005:单例模式(Singleton Pattern)

单例模式

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

1.解析单例模式是设计模式中最简单的形式之一。一个类有且仅有一个实例,并且自行实例化向整个系统提供。UML : 实现形式 : (1)恶汉式 (2)懒汉式 (常用) (3)双锁式2.实例恶汉式和...

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

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

设计模式(创建型)之单例模式(Singleton Pattern)

单例模式可能是23种设计模式中最简单的。应用也非常广泛,譬如Android中的数据库访问等操作都可以运用单例模式。核心概念: 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称...

设计模式总结之Singleton Pattern(单例模式)

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

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

设计模式——单例模式 简单快捷的了解设计模式
  • yk3372
  • yk3372
  • 2016年11月26日 17:04
  • 252
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:设计模式系列之一:单例模式(Singleton Pattern)
举报原因:
原因补充:

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