设计模式 Singleton 单例 懒汉,线程安全

原创 2015年07月09日 21:32:40

        首先来明确一个问题,那就是在某些情况下,有些对象,我们只需要一个就可以了,

比如,一台计算机上可以连好几个打印机,但是这个计算机上的打印程序只能有一个,

这里就可以通过单例模式来避免两个打印作业同时输出到打印机中,

即在整个的打印过程中我只有一个打印程序的实例。

 一、基本定义                                            

        通过上面简单介绍,我们可以对单例模式有一个简单的认识。所谓单例模式就是确保某一个类只有一个实例,并

且提供一个全局访问点。

        从上面可以看出单例模式有如下几个特点:

           一、它只有一个实例。

           二、它必须要自行实例化。

           三、它必须自行想整个系统提供访问点。


简单说来,单例模式(也叫单件模式)的作用就是保证在整个应用程序的生命周期中,

任何一个时刻,单例类的实例都只存在一个(当然也可以不存在)。

  二、实现                                                                        

public class SingletonClass {

  private static SingletonClass instance = null;
    
  public static SingletonClass getInstance() {
    if(instance == null) {
      instance = new SingletonClass();
    }
    return instance;
  }
    
  private SingletonClass() {
    
  }
    
}

同步:


上面的代码很清楚,也很简单。然而就像那句名言:“80%的错误都是由20%代码优化引起的”。单线程下,这段代码没有什么问题,可是如果是多线程,麻烦就来了。我们来分析一下:
 
线程A希望使用SingletonClass,调用getInstance()方法。因为是第一次调用,A就发现instance是null的,于是它开始创建实例,就在这个时候,CPU发生时间片切换,线程B开始执行,它要使用SingletonClass,调用getInstance()方法,同样检测到instance是null——注意,这是在A检测完之后切换的,也就是说A并没有来得及创建对象——因此B开始创建。B创建完成后,切换到A继续执行,因为它已经检测完了,所以A不会再检测一遍,它会直接创建对象。这样,线程A和B各自拥有一个SingletonClass的对象——单例失败


public class SingletonClass {
    
  private static class SingletonClassInstance {
    private static final SingletonClass instance = new SingletonClass();
  }

  public static SingletonClass getInstance() {
    return SingletonClassInstance.instance;
  }

  private SingletonClass() {

  }
    
}
三、多线程问题解决方案

这里有三种解决方案:

第一、  使用synchronized来处理。也就是说将getInstance()方法变成同步方法即可。

public class Singleton {
	//利用静态变量来记录Singleton的唯一实例
	private static Singleton uniqueInstance;
	
	/*
	 * 构造器私有化,只有Singleton类内才可以调用构造器
	 */
	private Singleton(){
		
	}
	// 同步 getInstance 方法
	public static synchronized Singleton getInstance(){
		if(uniqueInstance == null){
			uniqueInstance = new Singleton();
		}
		
		return uniqueInstance;
	}
	
}
第二、  懒加载 直接初始化静态变量。这样就保证了线程安全

public class Singleton {
    /*
     * 利用静态变量来记录Singleton的唯一实例
     * 直接初始化静态变量,这样就可以确保线程安全了
     */
    private static Singleton uniqueInstance = new Singleton();
    
    /*
     * 构造器私有化,只有Singleton类内才可以调用构造器
     */
    private Singleton(){
        
    }
    
    public static Singleton getInstance(){
        return uniqueInstance;
    }
    
}

 第三、  用“双重检查加锁”,在getInstance()中减少使用同步

public class Singleton {
	/*
	 * 利用静态变量来记录Singleton的唯一实例
	 * volatile 关键字确保:当uniqueInstance变量被初始化成Singleton实例时,
	 * 多个线程正确地处理uniqueInstance变量
	 * 
	 */
	private volatile static Singleton uniqueInstance;
	
	/*
	 * 构造器私有化,只有Singleton类内才可以调用构造器
	 */
	private Singleton(){
		
	}
	
	/*
	 * 
	 * 检查实例,如果不存在,就进入同步区域
	 */
	public static Singleton getInstance(){
		if(uniqueInstance == null){
			synchronized(Singleton.class){    //进入同步区域
				if(uniqueInstance == null){     //在检查一次,如果为null,则创建
					uniqueInstance  = new Singleton();
				}
			}
		}
		
		return uniqueInstance;
	}
	
} 


很显然第三种是最好的,一,如果不使用不会占用内存,二 效率也比较高;

  四、模式优缺点                                                                                                           

           优点

              一、节约了系统资源。由于系统中只存在一个实例对象,对与一些需要频繁创建和销毁对象的系统而言,单

例模式无疑节约了系统资源和提高了系统的性能。

             二、因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它。

         缺点

             一、由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。

             二、单例类的职责过重,在一定程度上违背了“单一职责原则”。


           五、模式使用场景                                                                                                     

           下列几种情况可以使用单例模式。

              一、系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器,或者需要考虑资源消耗太大而只允许创建一个对象。

             二、客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。

           六、总结                                                                                                                    

           1. 单例模式中确保程序中一个类最多只有一个实例。

           2. 单例模式的构造器是私有了,而且它必须要提供实例的全局访问点。

           3. 单例模式可能会因为多线程的问题而带来安全隐患。




             一、由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。

             二、单例类的职责过重,在一定程度上违背了“单一职责原则”。



版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

【设计模式】单例模式的绝对单例及线程安全

一、饿汉模式/** * 饿汉模式 * @author 郑海鹏 * @since 2015年7月6日 */ public class Singleton { private static...
  • H28496
  • H28496
  • 2015-11-17 10:44
  • 1658

懒汉式单例设计模式线程不安全

懒汉式:延迟加载方式。(先不new,等用到的时候再进行实例化)单例设计模式点击查看 [java] view plain copy   class single2{       &...

单例设计模式详解一:不安全的懒汉式(多线程环境验证)

单例设计模式详解一:不安全的懒汉式(多线程环境验证)单例设计模式详解一不安全的懒汉式多线程环境验证 写在前面的话 饿汉式 懒汉式 验证在多线程环境下懒汉式单例写法的不安全之处 写在前面的话前言:虽然工...

黑马程序员-单例设计模式线程安全

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ------- 单例设计模式: 1、恶汉式 2、懒汉式 此处有三个考点: 1、懒汉式单例模...

Java设计模式(一):单例设计模式(singleton)之懒汉式

单例设计模式懒汉式设计: 一般来说,单例设计模式两种常用的设计方法就是饿汉式和懒汉式。两者的设计思路是一样的,只不过在实现的过程中有点小区别。具体在下面结合代码讲解。 第一步:定义私有的sta...

初学设计模式(3)-----单例模式(在研究单例的线程安全问题时,发现一篇很全面的文章,直接转了)

单例模式最要关心的则是对象创建的次数以及何时被创建。  Singleton模式可以是很简单的,它的全部只需要一个类就可以完成(看看这章可怜的UML图)。但是如果在“对象创建的次数以及何时被创建”...

多线程编程-线程安全问题浅谈(附懒汉式单例)

多个线程在操作go

设计一个线程安全的单例(Singleton)模式

在设计单例模式的时候,虽然很容易设计出符合单例模式原则的类类型,但是考虑到垃圾回收机制以及线程安全性,需要我们思考的更多。有些设计虽然可以勉强满足项目要求,但是在进行多线程设计的时候。不考虑线程安全性...

单例设计模式的分析(懒汉,饿汉式)

主要分析的是单例模式。包括懒汉式,饿汉式,登记式,以及懒汉式的改进型, 还有一个关于读取propertoes配置文件的实例。预计分为三节。这是第一节,先分析最简单的懒汉式和饿汉式。 单例模式是设计模...

理解单例设计模式(饿汉式,懒汉式,静态内部类,枚举,双重校验锁)

package com.test.singleton; /** * * Description:饿汉式单例类,在类初始化时,已经自行实例化 * 这种方式基于classLoder机制避免了多线...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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