关闭

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

454人阅读 评论(0) 收藏 举报
分类:

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

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

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

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

 一、基本定义                                            

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

且提供一个全局访问点。

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

           一、它只有一个实例。

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

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


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

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

  二、实现                                                                        

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. 单例模式可能会因为多线程的问题而带来安全隐患。




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

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



1
0
查看评论

java 单例模式之线程安全的饿汉模式和懒汉模式

单例模式 解决的问题:保证一个类在内存中的对象唯一性. 比如:多程序读取一个配置文件时,建议配置文件封装成对象。会方便操作其中数据,又要保证多个程序读到的是同一个配置文件对象,就需要该配置文件对象在内存中是唯一的。 如何保证对象唯一性呢? 思想: 1,不让其他程序创建该类对象。 2,在本类中创建一...
  • twj13162380953
  • twj13162380953
  • 2016-12-25 15:26
  • 1802

Java练习题-编写一个线程安全的延迟加载单例模式(懒汉模式)

懒汉模式通常会使用的这样的写法来实现:public class Singleton { private Singleton() {} private static Singleton instance = null; public static Singleton...
  • u012643122
  • u012643122
  • 2015-02-12 22:48
  • 1421

懒汉式单例模式的线程安全问题

新建一个单例模式类和一个多线程测试类 public class Test24 implements Runnable { public void run() { System.out.println(TestSingleton.getInstance()); } public stati...
  • u010584063
  • u010584063
  • 2015-07-11 09:24
  • 3443

java的线程安全、单例模式、JVM内存结构等知识学习和整理

知其然,不知其所以然 !在技术的海洋里,前路漫漫,我一直在迷失着自我。 欢迎访问我的csdn博客,我们一同成长!“不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!” 博客首页:http://blog.csdn.net/u010648555在下面的题目来自于我要加的一个QQ群,然后要加这个Q...
  • u010648555
  • u010648555
  • 2017-10-10 18:09
  • 812

如何创建线程安全的单例模式?线程安全的Singleton!

单例模式的概念 单例模式就是确保只有一个实例,而且自行实例化并向整个系统传递这个实例,这个类就称作为单例类 单例模式最重要的一个特点就是构造方法私有化。创建单例模式分为懒汉式和饿汉式。 第一种:懒汉式(线程不安全的) 传统的懒汉式创建单例模式,是线程不安全的 public clas...
  • a347911
  • a347911
  • 2016-11-24 16:59
  • 1444

python 线程安全的单例 singleton

import threading class Singleton(object):     __instant = None;     __lock = threading.Lock();     ...
  • JianDan110
  • JianDan110
  • 2011-09-02 14:16
  • 1782

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

在设计单例模式的时候,虽然很容易设计出符合单例模式原则的类类型,但是考虑到垃圾回收机制以及线程安全性,需要我们思考的更多。有些设计虽然可以勉强满足项目要求,但是在进行多线程设计的时候。不考虑线程安全性,必然会给我们的程序设计带来隐患。此处,我们不介绍什么是单例模式,也不介绍如何设计简单的设计模式,因...
  • gggg_ggg
  • gggg_ggg
  • 2015-12-08 09:43
  • 1914

C++中线程安全并且高效的singleton

Singleton是一个非常常用的设计模式。几乎所有稍大的程序都会用到它。所以构建一个线程安全,并且高效的singleton很重要。既然要讨论这个主题,我们就先来定义一下我们的需求: Lazy initialization。只有在第一次使用的时候才需要初始化出一个singleton对象。这使得...
  • janeqi1987
  • janeqi1987
  • 2017-07-26 15:20
  • 165

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

单例模式在23个设计模式中算得上是最简单的一个了,也行你会有异议,那就换成“最简单之一”,这样就严谨了很多。   单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。   适用性:当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。当这个唯一实例应该是通过子类化可扩展的,并...
  • u013256816
  • u013256816
  • 2016-03-23 21:37
  • 4934

C++单例模式以及线程安全

写一个单例模式:class MySingleton { public: static MySingleton * GetInstance() //static method that returns only instance of MySingletone { ...
  • wangshubo1989
  • wangshubo1989
  • 2016-09-18 13:31
  • 11448
    个人资料
    • 访问:349476次
    • 积分:3678
    • 等级:
    • 排名:第10489名
    • 原创:83篇
    • 转载:116篇
    • 译文:0篇
    • 评论:61条
    博客专栏
    说明
    Android 交流学习群 QQ:458506426