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()的时间耗费。

  • 相关阅读:
    Java基础——clone()方法浅析
    Unity shader error: “Too many texture interpolators would be used for ForwardBase pass”
    ar 解压一个.a文件报错: xxx.a is a fat file (use libtool(1) or lipo(1) and ar(1) on it)
    How to set up "lldb_codesign" certificate!
    Unity-iPhone has Conflicting Provisioning Settings
    ETC1/DXT1 compressed textures are not supported when publishing to iPhone
    Xcode 提交APP时遇到 “has one iOS Distribution certificate but its private key is not installed”
    XCode iOS之应用程序标题本地化
    苹果电脑(Mac mini或Macbook或iMac)恢复出厂设置
    Unity 4.7 导出工程在XCode10.1上编译报错
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/5125217.html
Copyright © 2011-2022 走看看