设计模式之单例模式

原创 2013年12月04日 00:40:34

一、简介

1、单例模式是一种对象创建模式,用于产生一个对象的具体实例,它可以确保系统中一个类只产生一个实例。

2、在Java中,单例模式带来的好处如下:

  • 对于频繁使用的对象,可以省去创建对象所花费的时间。
  • 由于使用new关键字操作的次数减少,所以对系统内存的使用频率也会降低,这将减轻GC的压力,缩短GC停顿时间。

二、单例模式类图

1、单例模式的参与者只有单例类和使用者,其中单例类提供单例的工厂,返回单例对象;而使用者获取并使用单例类。如下图:

三、Java语言实现单例模式

1、方式一

如下代码所示,单例类的构造方法必须私有化,这样才能确保单例类不会在系统中的其它代码内被实例化。

public class Singleton {
	
	private static Singleton instance = new Singleton();

	// 构造方法私有化
	private Singleton() {
		
	}
	
	public static Singleton getInstance() {
		return instance;
	}
}

缺点:无法对instance实例做延迟加载。由于instance变量是static定义的,所以在JVM加载单例类后,首次主动使用单例类时,单例对象就会被创建。如果该单例类在系统中还扮演了其它的角色,那么在任何使用这个单例类的地方都会初始化instance变量,而不管是否被用到。

2、方式二

如下代码所示,这种方式就能达到延迟加载的要求,但是getInstance方法必须是同步的,否则在多线程环境下,可能会导致多个实例被创建

public class Singleton {
	
	private static Singleton instance;

	// 构造方法私有化
	private Singleton() {
		
	}
	
	public static synchronized Singleton getInstance() {
		if (instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
}

缺点:由于引入了同步关键字,在多线程环境下它的时耗要远远大于第一种实现方式。

3、方式三

如下代码所示,单例模式使用内部类来维护单例类的实例,当Singleton类被加载时,其内部类并不会被初始化,所以可以确保当Singleton类被载入JVM时,不会初始化单例类;而当getInstance方法被调用时,才会去加载SingletonHolder类,而当执行SingletonHolder.instance时,由于是对SingletonHolder类的首次主动使用,所以此时才会初始化instance。同时,由于实例的建立是在类加载时完成,所以天生对多线程友好,getInstance方法不再需要使用同步关键字。

public class Singleton {
	
	// 构造方法私有化
	private Singleton() {
		
	}
	
	private static class SingletonHolder {
		private static Singleton instance = new Singleton();
	}
	
	public static Singleton getInstance() {
		return SingletonHolder.instance;
	}
}

优点:使用内部类方式实现单例,既可以做到延迟加载,也不必使用同步关键字。

四、单例的序列化与反序列化

1、一般情况下,用以上方式实现的单例可以确保在系统中只存在唯一实例了,但也有例外的情况导致系统可能生成多个实例,比如通过反射强行调用单例类的私有构造方法,生成多个实例。还有通过序列化与反序列化时,也可能生成多个实例对象,如下代码:先将单例对象序列化,然后反序列化,以下代码中的s1和s2都是同一个对象,但是当去掉Singleton类的readResolve方法时,s1和s2就是两个不同的对象了,在反序列化后就生成了多个单例对象了。

class Singleton implements Serializable{
	
	private static Singleton instance = new Singleton();

	// 构造方法私有化
	private Singleton() {
		
	}
	
	public static Singleton getInstance() {
		return instance;
	}
	
	//阻止生成新的实例,总是返回当前对象
	private Object readResolve() {
		return instance;
	}
}

public class SingletonMain {
	public static void main(String[] args) throws IOException, ClassNotFoundException {
		Singleton s1 = Singleton.getInstance();
		//将s1序列化
		OutputStream os = new FileOutputStream("Singleton.txt");
		ObjectOutputStream oos = new ObjectOutputStream(os);
		oos.writeObject(s1);
		oos.flush();
		oos.close();
		
		//反序列化
		InputStream is = new FileInputStream("Singleton.txt");
		ObjectInputStream ois = new ObjectInputStream(is);
		Singleton s2 = (Singleton) ois.readObject();
		ois.close();
		System.out.println(s1 == s2);
	}
}

原因:在实现了私有的readResolve方法后,ObjectInputStream类的readObject()方法已经形同虚设,它直接使用readResolve方法的返回值替换了原本的返回值,这是一种在形式上构造了单例。

所以序列化和反序列化可能会破坏单例。




 

相关文章推荐

设计模式学习之单例模式

  • 2013年12月11日 21:43
  • 5KB
  • 下载

23钟设计模式之单例模式

  • 2013年08月13日 10:41
  • 26KB
  • 下载

设计模式之———单例模式的问题及效率比较

目录 - 出现问题 - 问题展示及解决方法 - 不同单例模式的效率比较
  • lyyao09
  • lyyao09
  • 2016年09月29日 16:42
  • 656

设计模式之单例模式程序

  • 2010年05月18日 10:28
  • 3KB
  • 下载

java设计模式之单例模式详解

  • 2012年11月02日 17:53
  • 33KB
  • 下载

设计模式--单例模式【Singleton Pattern】

这个模式是很有意思,而且比较简单,但是我还是要说因为它使用的是如此的广泛,如此的有人缘,单例就是单一、独苗的意思,那什么是独一份呢?你的思维是独一份,除此之外还有什么不能山寨的呢?我们举个比较难复制的...

设计模式单例模式

  • 2014年10月10日 20:56
  • 4KB
  • 下载

【OC加强】单例模式与[NSFileManager defaultMagager]以及其他设计模式

这个类的defaultManager方法利用的是一种单例模式,即只要这个程序还在运行,那么整个运行期间只能存在1个单例,即1个实例对象。...

设计模式之单例模式

  • 2012年04月10日 17:38
  • 728B
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:设计模式之单例模式
举报原因:
原因补充:

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