`
zhouwenjian
  • 浏览: 14225 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Singleton(二)

 
阅读更多

0)Eager initialization

如果程序一开始就需要某个单例,并且创建这个单例并不那么费时,我们可以考虑用这种方式:

1
2
3
4
5
6
7
8
9
public class Singleton {
    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {}

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

这种实现方式有几个特点:

  • 实例一开始就被创建(Eager initialization)。
  • getInstance()方法不需要加synchronize来解决多线程同步的问题。
  • final关键字确保了实例不可变,并且只会存在一个。

1)Lazy initialization

懒加载的方式使得单例会在第一次使用到时才会被创建.先看一种有隐患的写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public final class LazySingleton {
  private static volatile LazySingleton instance = null;

  // private constructor
  private LazySingleton() {
  }

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

请注意:上面的写法其实非线程安全的,假设两个Thread同时进入了getInstance方法,都判断到instance==null,然后会因为synchronized的原因,逐个执行,这样就得到了2个实例。解决这个问题,需要用到典型的double-check方式,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class LazySingleton {
    private static volatile LazySingleton instance = null;

    private LazySingleton() {       
    }

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

另外一个更简略直观的替代写法是:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class LazySingleton {
    private static volatile LazySingleton instance = null;

    private LazySingleton() {       
    }

    public static synchronized LazySingleton getInstance() {
            if (instance == null) {
                instance = new LazySingleton ();
            }
        return instance;
    }
}

2)Static block initialization

如果我们对程序的加载顺序有点了解的话,会知道Static block的初始化是执行在加载类之后,Constructor被执行之前。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class StaticBlockSingleton {
  private static final StaticBlockSingleton INSTANCE;

  static {
      try {
          INSTANCE = new StaticBlockSingleton();
      } catch (Exception e) {
          throw new RuntimeException("Error, You Know This, Haha!", e);
      }
  }

  public static StaticBlockSingleton getInstance() {
      return INSTANCE;
  }

  private StaticBlockSingleton() {
      // ...
  }
}

上面的写法有一个弊端,如果我们类有若干个static的变量,程序的初始化却只需要其中的1,2个的话,我们会做多余的static initialization。

3)Bill Pugh solution

University of Maryland Computer Science researcher Bill Pugh有写过一篇文章initialization on demand holder idiom

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Singleton {
    // Private constructor prevents instantiation from other classes
    private Singleton() { }

    /**
    * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
    * or the first access to SingletonHolder.INSTANCE, not before.
    */
    private static class SingletonHolder {
        public static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

SingletonHolder类会在你需要的时候才会被初始化,而且它不影响Singleton类的其他static成员变量的使用。这个方法是线程安全的并且避免了使用volatile与synchronized。

4)Using Enum

这是最简便安全的方法。没有明显的缺点,并且避免了下面要讲到的序列化的隐患。

1
2
3
4
5
6
public enum Singleton {
    INSTANCE;
    public void execute (String arg) {
        // perform operation here 
    }
}

Serialize and de-serialize

在某些情况下,需要实现序列化的时候,普通的单例模式需要添加readResolve的方法,不然会出现异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class DemoSingleton implements Serializable {
  private volatile static DemoSingleton instance = null;

  public static DemoSingleton getInstance() {
      if (instance == null) {
          instance = new DemoSingleton();
      }
      return instance;
  }

  protected Object readResolve() {
      return instance;
  }

  private int i = 10;

  public int getI() {
      return i;
  }

  public void setI(int i) {
      this.i = i;
  }
}

仅仅有上面的还不够,我们需要添加serialVersionUID,例子详见下面的总结。

Conclusion

实现一个功能完善,性能更佳,不存在序列化等问题的单例,建议使用下面两个方式之一:

Bill Pugh(Inner Holder)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class DemoSingleton implements Serializable {
  private static final long serialVersionUID = 1L;

  private DemoSingleton() {
      // private constructor
  }

  private static class DemoSingletonHolder {
      public static final DemoSingleton INSTANCE = new DemoSingleton();
  }

  public static DemoSingleton getInstance() {
      return DemoSingletonHolder.INSTANCE;
  }

  protected Object readResolve() {
      return getInstance();
  }
}

Enum

1
2
3
4
5
6
public enum Singleton {
    INSTANCE;
    public void execute (String arg) {
        // perform operation here 
    }
}

参考资料

分享到:
评论

相关推荐

    singleton_duplication:在Windows上链接在一起的共享库中使用时,单例的复制

    'lib b' => 'after main'~Singleton()一个简单的Windows安装程序会将Singleton复制到每个二进制文件中: Singleton()[140701732254544] 'unset' => 'before main'Singleton()[140732774888256] 'unset' => 'lib a'...

    设计模式手册 图表例子完全

    代码例子是C++和C#的 chm格式 一、创建型 FactoryMethod Abstract Factory Builder Prototype Singleton 二、结构型 Adapter_Class Adapter_Object Bridge 等等 三、行为型 Interpreter TemplateMethod等等

    C#面向对象设计模式纵横谈-1.Singleton 单件(创建型模式)

    C#面向对象设计模式纵横谈 第二课 Singleton 单件(创建型模式)

    C#设计模式之Singleton模式

    Singleton是二十三个设计模式中比较重要也比较经常使用的模式。但是这个模式虽然简单,实现起来也会有一些小坑,让我们一起来看看吧! 实现思路 首先我们看看这个设计模式的UML类图。 很清晰的可以看到,有三点是...

    objc-singleton:如何实现安全的 Objective-C 单例

    第二点在场景上看起来有些吹毛求疵,用户可以粘贴示例代码或是看一下文档可以做到通过工厂方法获得单例,规避这个问题。 在各篇Objective C Singleton文章中这方面几乎都没有得到重视,但对于API的用户上是有意义的...

    Java单例模式.docx

    o意:两个校验都必须加,如果第二个没有加校验,当两个线程都通过了第一个if校验,此时会有一个线程进入同步代码块,创建singleton实例,接着第二个线程也会进入同步代码块,并会在创建一个singleton。那么这样就...

    最新二级缓存memcached,支持hibernate4

    解决目前memcached不支持hibernate4的缺陷,hibernate配置<property name="hibernate.cache.region.factory_class">com.googlecode.hibernate.memcached.MemcachedRegionFactory</property>

    金山软件2011年C++高级开发岗位(Linux)笔试题

    一、我们说正方形是矩形,但如果把这种...二、请用 C++实现 Singleton 模式,需考虑一下问题: 1. 延迟创建,在 Singleton 的实例真正需要用到时才创建; 2. 线程安全; 3. Singleton 实例中的资源能在恰当的时机释放。

    学习php设计模式 php实现单例模式(singleton)

    Singleton 定义一个Instance操作,允许客户访问它的唯一实例。Instance是一个类方法。负责创建它的唯一的实例。 三、单例模式的优点 1、对唯一实例的受控访问 2、缩小命名空间 单例模式是对全局变量的一种改进。它...

    设计模式,软件开发者必读

    设计模式的个人总结教材,适合IT专业人士研究,目录如下: 序言 概念 6 1.1 设计模式的定义 6 1.2 设计模式的作用 6 ...5.3 虚函数和多态性(二) 114 5.4 C++中的纯虚函数 116 5.5 多继承,RTTI和虚函数 118

    C#基础之yield与Singleton

    yield这个关键字作用于迭代器块中,其本质的功能有2个:一是“依次”向枚举对象提供值,二是发出迭代结束信号。这两个功能对应的语句分别是yield return和yield break。下面有2个小例子,分别没有使用yield和有使用...

    Spring并发访问的线程安全性问题.docx

    这也许就是他和struts2的区别吧和Struts一样,Spring的Controller默认是Singleton的,这意味着每个request过来,系统都会用原有的instance去处理,这样导致了两个结果:一是我们不用每次创建Controller,二是减少了...

    java开发大猫聊天室源码-dp:设计模式学习

    方式二 public class Singleton2 { private static final Singleton2 INSTANCE; static { INSTANCE = new Singleton2(); } public static Singleton2 getInstance() { return INSTANCE; } } 可以通过如下反射方式...

    C#设计模式大全

    二、 Singleton模式的结构: 三、 程序举例: 四、 在什么情形下使用单例模式: 五、 Singleton模式在实际系统中的实现 六、 C#中的Singleton模式 C#设计模式(8)-Builder Pattern 一、 建造者(Builder)...

    网络编程、常用设计模式

    一、单态模式(Singleton Pattern) 19 二、单态类的特性 19 三、饿汉式单态类 19 四、懒汉式单态类 20 五、两种单态的区别 20 【二】、装饰者模式 20 一、装饰者模式(Decorator Pattern) 20 二、装饰者模式的特性 21 ...

    二十三种设计模式【PDF版】

    设计模式之 Singleton(单态/单件) 阎宏博士讲解:单例(Singleton)模式 保证一个类只有一个实例,并提供一个访问它的全局访问点 设计模式之 Factory(工厂方法和抽象工厂) 使用工厂模式就象使用 new 一样频繁. ...

    Java设计模式之单例模式及其应用

     二、单例模式的几种形式  1. 饿汉式单例 public class Singleton { private static final Singleton singleton= new Singleton(); private Singleton(){ } public Singleton getSingleton(){ return sin

    C#设计模式.PDF

    二、 Singleton模式的结构: 51 三、 程序举例: 51 四、 在什么情形下使用单例模式: 52 五、 Singleton模式在实际系统中的实现 53 六、 C#中的Singleton模式 55 C#设计模式(8)-Builder Pattern 57 一、 建造者...

    敏捷软件开发:原则、模式与实践.pdf

    第十六章 SINGLETON模式和MONOSTATE模式 第十七章 NULL OBJECT模式 第十八章 薪水支付案例研究:第一次迭代开始 第十九章 薪水支付案例研究:实现 第Ⅳ部分 打包薪水支付系统 第二十章 包的设计原则 第二十一章 ...

    敏捷软件开发:原则、模式与实践

    第十六章 SINGLETON模式和MONOSTATE模式 第十七章 NULL OBJECT模式 第十八章 薪水支付案例研究:第一次迭代开始 第十九章 薪水支付案例研究:实现 第Ⅳ部分 打包薪水支付系统 第二十章 包的设计原则 第二十一章 ...

Global site tag (gtag.js) - Google Analytics