再考虑singleton在Java中的实现的一些问题

Monday, August 25th, 2008 61 views

之前的一篇文章:设计模式学习笔记:单例(singleton)模式主要介绍了单例模式的概念,及在Java中的实现,并给出了多线程环境的解决方法。

习惯上,保证一个类的实例是唯一的,主要通过使得构造器私有,通过静态工厂方法来控制实例的产生。这样做常常是有效的。但是,它并不能够真正保证类的实例是唯一的,因为,要产生一个类的实例,不一定需要经过构造器(Java语言的前提下)。

假使这个类或者其父类实现了Serializable接口,要保证该类实例的唯一性就不是那么简单了。首先,在Java1.2之前的版本中,我们是没有办法保证它唯一性的。因此,一个单例的类不应当实现Serializable接口。在Java1.2和之后的版本,开始有了解决的方法。我们需要提供一个readResolve方法,在Effective Java第57条建议中,保证singleton的readResolve方法如下:

1
2
3
private Object readResolve() throws ObjectStreamException{
             return INSTANCE;
}

还有一种创建实例不需要经过构造器的情况是类或者父类声明了Cloneable接口,这个时候有必要重载clone方法来保证唯一性。

1
2
3
4
public Object clone(){
           return this;
           // or throw CloneNotSupportedException;
}

设计模式学习笔记:单例(singleton)模式

Monday, July 28th, 2008 47 views

From Wikipedia: the singleton pattern is a design pattern that is used to restrict instantiation of a class to one object.

文中关于设计模式的描述与实现很可能跟Java语言特性有关。

单例模式是很简单的一种设计模式,它的主要目的是保证在程序运行过程中,某个特定的类只存在一个实例。很多时候,我们采用将类的成员和方法静态化也可以实现这样的需求。有的时候,这样做是无伤大雅的,但是有的时候采用静态方法来替代单利模式是不恰当的。且这还会跟具体的语言特性相关。

Java采用构造器来创建一个新的实例,因此只需要将构造器设为私有,便可以阻止其他类不负责任的随意构造实例,同时,我们还需要有一个静态的方法来返回或者构造一个实例。简单代码如下:

1
2
3
4
5
6
7
8
9
10
11
public class Singleton{
        private static Singleton foo;
        private Singleton(){}
        /*
         a lot of other codes here
        */
        public Singleton getInstance(){
                 if(foo==null) foo=new Singleton();
                 return foo;
        }
}

可以看到,单例模式无论从概念上还是实现上都是比较简单的。但是,如果我们的代码运行在多线程环境中,会发生什么情况呢?如果运气足够的不好,方法getInstance()可能同时由几个线程在调用,而此时恰好foo还是null,那么就会创建多个实例。我们的getInstance方法不是线程安全的,如何解决呢?

方法1:getInstance()方法仅仅在实例还没有被创建的时候才会出现线程不安全的问题,如果我们非常早的就创建了实例,那么就没有这个问题了,比如这样:

1
  private static Singleton foo=new Singleton();

因此,解决单例模式线程安全问题一种方法就是非常早的实例化

方法2:利用Java的同步机制,对getInstance()方法加锁,可以彻底避免线程安全问题,比如:

1
  synchronized getInstance(){..

,这种方法能解决问题,但是性能相当底下,不推荐使用。

方法3:同方法2一样的思路,只是不是对方法本身加锁,而只是对方法内部其中的一块加锁。这种特性只有Java5.0以后才支持。真正造成线程安全问题的是getInstance中创建实例的部分,只需要同步这部分即可。

1
2
3
4
5
6
7
8
  public Singleton getInstance(){
           if(foo==null) {
                  synchronized {
                      if(foo==null)    foo=new Singleton();
                  }
              }
           return foo;
        }

关于

我叫陈炬,正在天津大学计算机学院->知识工程与科学研究所攻读硕士研究生。今年应届。您可以在我的自我介绍获得更多关于我的信息

订阅我的Blog


本站RSS地址| [这是什么?]
订阅到Google Reader | 订阅到 抓虾 阅读器 | 订阅到 鲜果 阅读器

其他blog

我还有一个英文blog,非常的无聊,琐碎,许多的语法错误。请谨慎访问。
Find entries :