现在的位置: 首页 > 综合 > 正文

Singleton模式

2013年08月26日 ⁄ 综合 ⁄ 共 2148字 ⁄ 字号 评论关闭

    这么晚了,本来打算看看Singleton这个简单的设计模式就睡觉去的。结果找了zuoxiolong8810大神对Singleton模式的诠释,顿时就晕晕乎乎了,我还以为这模式简单着呢,没想到背后道理还蛮多的。

    Singleton模式适用于那些如果有两个或者两个以上的实例会引起错误的类,或者说没有状态的类。

    先写一个最原始的单例模式吧!(本来打算用C++写的,看了K_chen的资料,没有写到支持并发的单例,而且用C++写并发的程序,不太好看,同时我对同步还不是很熟悉,所以就用java吧!)

public class Singleton {
	private static Singleton mInstance = null;
	
	private Singleton(){}
	
	public static Singleton GetInstance()
	{
		if(mInstance == null)
		{
			mInstance = new Singleton();
		}
		return mInstance;
	}
}

class App
{
	public static void main(String[] args) {
		Singleton inst = Singleton.GetInstance();
		System.out.println("Over!");		
	}
}

蛋疼,以前不管有没有用到多线程,我都用的这种写法啊,也没发现有啥错,可能是自己经验太浅了吧。

zuoxiolong8810说的很通俗,显然,这种原始的写法是不能处理并发操作的。

public class Singleton {
	private static Singleton mInstance = null;
	
	private Singleton(){}
	
	public static Singleton GetInstance()
	{
		if(mInstance == null)
		{
			synchronized (Singleton.class) {
				if(mInstance == null){								
					mInstance = new Singleton();
				}
			}			
		}
		return mInstance;
	}
}

class App
{
	public static void main(String[] args) {
		Singleton inst = Singleton.GetInstance();
		System.out.println("Over!");		
	}
}

稍稍解释一下这里为啥在临界区代码又加了一个判断语句吧,如果有两个线程A和B都通过了第一个

if(mInstance == null)的判断,这时,假设A进入了临界区,成功创建了对象后,退出临界区。这时候,因为B已经经历了第一层检查,如果没有第二层检查的话,它仍然会创建一个对象,显然不符合单例模式的初衷。

我还以为单例模式到这儿就完了,没想到还有下文。

因为JVM的原因,上述写法仍然产生错误(具体啥原因可以去zuoxiolong8810的博客,解释的很清楚)。下面贴出两种标准的写法,像这种写法,还是记下来为妙。

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

class App
{
	public static void main(String[] args) {
		Singleton inst = Singleton.GetInstance();
		System.out.println("Over!");		
	}
}

加上volatile关键字后,可以保证变量的所有读取操作时不可拆分的,也就保证了变量的初始化过程是不可拆分的,因而可以屏蔽掉因为JVM优化指令而带来的影响。

还有一种写法是值得推荐的,写起来比较简单,也更利于理解。

public class Singleton {
	
	private static class InnerSingleton{
		protected static Singleton mInstance = new Singleton();
	}
	
	private Singleton(){}
	
	public static Singleton GetInstance()
	{
		return InnerSingleton.mInstance;
	}
}

class App
{
	public static void main(String[] args) {
		Singleton inst = Singleton.GetInstance();
		System.out.println("Over!");		
	}
}

很简洁,解释是:"JVM会保证类的静态属性在第一次加载时初始化,并且这个过程不会打断";既然是JVM管的,看完这句话我就放心了,因为终于看完了这个模式,可以睡觉去了。

至于为什么要弄一个内部类,是因为为了防止在使用其他Singleton的静态属性时创建这个类(如果系统一直没有用到这个类的话,就不必要创建了)带来的可能比较大的内存和时间开销。




抱歉!评论已关闭.