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;
} |
Posted in Java, 设计模式 | 2 Comments »
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;
} |
Posted in 设计模式 | 1 Comment »