zoukankan      html  css  js  c++  java
  • 设计模式之---单例模式

    设计模式的世界中,单例模式可能是最简单的一种模式,虽说简单。但想要彻底的弄明确它。还是要经历一点点的波折。

    以下我为大家慢慢道来:


    在实际开发中,对于有些对象。我们仅仅须要一个,比方线程池(thread pool),缓存(cache),对话框。日志对象,任务管理器等等。

    这些对象仅仅能有一个实例。假设出现多个实例,则会导致很多问题的产生。


    你可能会说,我们为什么不用java的全局变量,多方便的。是的。可是这样做是有缺点的,假设我们将一个对象赋值给一个全局变量,那么我们在程序一開始就必须创建好对象,一旦这个对象很耗费资源。而程序在运行中又一直没实用到它,那么这样是很的浪费。


    单例模式。要保证一个对象仅仅能被实例化一次。我们先来看一段雏形代码:

    public class Singleton {
    	private static Singleton uniqueInstance;
    	private Singleton(){}
    	
    	public static Singleton getInstance(){
    		if(uniqueInstance==null){
    			uniqueInstance = new Singleton();
    		}
    		return uniqueInstance;
    	}
    }

    在这里,我们利用一个静态变量来记录Singleton类的唯一实例。并把构造方法设置为私有,那么仅仅有在Singleton类内部才干够调用此构造方法。然后我们用getInstance()方法实例化对象,并返回这个实例。

    假设uniqueInstance是空的,表示还没有创建实例,假设不为空,表示之前已经创建过对象。则直接跳过至return语句。


    可是细致想想。就会发现,上面的代码是有些问题的,问题在哪里呢?


    假设我们想应用多线程。那么假设有两个或两个以上的线程要运行上面这段代码,则可能会出现产生多个实例对象的情况,也就是说,没有同步机制。可能两个线程都运行到了uniqueInstance==null的情况。那么之后就会产生两个object。而这种结果就是不正确的。


    这是你可能会说,给方法加synchronizedkeyword啊,是的。于是有了以下的代码:

    public class Singleton {
    	private static Singleton uniqueInstance;
    	private Singleton(){}
    	
    	public static synchronized Singleton getInstance(){
    		if(uniqueInstance==null){
    			uniqueInstance = new Singleton();
    		}
    		return uniqueInstance;
    	}
    }

    这样。我们通过添加synchronizedkeyword到getInstance()方法中,能够使得每一个线程在进入这种方法之前,要先等候别的线程离开该方法。也就是说不会有两个线程能够同一时候进入该方法。


    可是这样做的问题是什么?细致想想。非常easy。那就是:同步会减少性能


    也就是说,我们仅仅有第一次运行此方法的时候才须要同步。一旦设置好了uniqueInstance变量。就不再须要同步这种方法了。由于仅仅有第一次unqueInstance==null,之后每次调用这种方法。同步都是多余的,甚至是一种累赘。


    所以,有时候要依据情况灵活的应对。


    假设getInstance()的性能相应用程序不是非常重要,那就什么都别做,可是必需要知道的是,同步一个方法可能会造成程序运行的效率下降100倍。所以非常多时候,我们就要又一次考虑了。


    当然。假设我们有时非常急切的须要创建实例。而不用延迟实例化的做法,就是在静态初始化器中创建单例,如以下的代码:

    public class Singleton {
    	private static Singleton uniqueInstance=new Singleton();
    	private Singleton(){}
    	
    	public static synchronized Singleton getInstance(){
    		return uniqueInstance;
    	}
    }

    并且这段代码是线程安全的。


    以下我们来看单例模式的终于版:

    双重检查加锁,在getInstance()中降低使用同步:

    利用双重检查加锁(double-checked locking)。首先检查是否实例已经创建了,假设未创建,才进行同步。这样。仅仅有第一次会同步。而这正是我们想要的:

    public class Singleton {
    	private volatile static Singleton uniqueInstance;
    	private Singleton(){}
    	
    	public static Singleton getInstance(){
    		if(uniqueInstance==null){
    			synchronized (Singleton.class){
    				if(uniqueInstance==null){
    					uniqueInstance = new Singleton();
    				}
    			}
    		}
    		return uniqueInstance;
    	}
    }

    volatilekeyword,用来确保将变量的更新操作通知到其它线程。保证新值能马上同步到主内存,以及每次使用前马上从主内存刷新。当把变量声明为volatile后,编译器与执行时都会注意到这个变量是共享的。

    在这里,volatilekeyword确保了,当uniqueInstance变量被初始化成Singleton实例时,多个线程能正确的处理uniqueInstance变量。

    假设性能是你关系的重点,那么这个做法能够帮你大大降低getInstance()的时间耗费。

  • 相关阅读:
    《The One!》团队作业4:基于原型的团队项目需求调研与分析
    《TheOne团队》团队作业三:团队项目原型设计与开发
    《The One 团队》第二次作业:团队项目选题
    《The One!团队》第一次作业:团队亮相
    实验十 团队作业6:团队项目系统设计改进与详细设计
    易校园——项目系统设计与数据库设计
    易校园--项目需求分析
    软工实践——团队上机作业
    团队编程第一次作业
    《发际线总是和我作队》第六次作业:团队项目系统设计改进与详细设计
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/5125217.html
Copyright © 2011-2022 走看看