您的位置:首页 > 其它

[设计模式]Singleton - 单例模式

2013-09-15 22:31 309 查看
  在写代码的过程中,我们会发现有些对象,其实我们只需要一个实例,比方说:线程池(threadpool)、日志对象等,这时候就需要用到“单例模式”,可以创建唯一的实例。

  简单的单例模式的代码如下:

package com.geekyjane.cnblogs.singleton;

public class Singleton {
private static Singleton uniqueInstance;

private Singleton() {
}

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


  要满足“只创建一个实例”的条件,就必须禁止其他的类实例化该类,通过自己提供类型实例来控制实例的唯一性。对于有些对象,实例化起来非常耗费资源,而程序在某次执行过程中又有一直没用到它,这样就会造成一种浪费,所以用了lazy instantiaze(延迟实例化),可以在需要的时候再进行实例的创建,从而避免了这样的一种浪费。

  但这也造成了一个多线程的问题,当两个线程AB,当A进入getInstance()方法,检测到uniqueInsatance为空,会通过new Singleton()来创建一个新的对象实例,而这时线程B也进入了该方法,发现uniqueInstance还没有创建出来(为空),也做了uniqueInstance = new Singleton()的操作,我们就会得到两个该对象的实例,这不符合单例模式的要求。

  所以对于多线程来说,我们要考虑线程安全。有三种方法,第一种是拒绝延迟实例化,第二种是同步该刚发,第三种是双重检查加锁(double-checked locking)。

package com.geekyjane.cnblogs.singleton;

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

private Singleton() {
}

public static Singleton getInstance() {
return uniqueInstance;
}
}


  对于第一种来说,是最简单快捷的,但是必然是没有延迟实例化来得好,所以不推荐。

package com.geekyjane.cnblogs.singleton;

public class Singleton2 {
private static Singleton2 uniqueInstance;

private Singleton2() {
}

public static synchronized Singleton2 getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton2();
}
return uniqueInstance;
}
}


  这种方法快捷有效,但是同步会降低性能,而且每一次取得实例时都要同步,这是一种累赘。所以如果你的应用程序要频繁运行getInstance方法,那还是放弃这个选择吧。

package com.geekyjane.cnblogs.singleton;

public class Singleton3 {
private volatile static Singleton3 uniqueInstance;

private Singleton3() {
}

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


  这种方法避免了方法二的缺点,首先检查是否实例已经创建了,如果尚未创建,才进行同步。这样做可以大大减少getInstance的耗时。但是如果你的代码不需要性能上的考虑,这么写似乎又会有些麻烦了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: