设计模式5—单件模式

来源:互联网 发布:linux脚本while循环 编辑:程序博客网 时间:2024/04/29 13:07

有些对象只需要一个,创建独一无二的实例,比如说:线程池(threadpool)、缓存(cache)、对话框、处理偏好设置和注册表(registry)的对象、日志对象、充当打印机、显卡等设备的驱动程序的对象。事实上,这些类对象只能由一个实例,如果制造出多个实例,就会导致很多问题产生,例如:程序的行为异常、资源使用过量,或者是结果不一致。


单件模式:单件模式确保一个类只有一个实例,并提供一个全局访问点。


public class Singleton {
private static Singleton uniqueInstance;

private Singleton() {}

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


理解:

1)我们把某个类设计成自己管理的一个单独实例,同时也避免其他类再自行产生实例。要想取得单件实例,通过单件类是唯一的途径

2)我们也提供对这个实例的全局访问点:当你需要实例时,向类查询,他会返回某个单个实例。利用延迟实例化的方式创建单件,这种做法对资源敏感的对象特别重要


看看类图:

getInstance()方法是静态的,这意味着它是一个类方法,所以可以在代码的任何地方使用Singleton.getInstance()访问它。这和访问全局变量一样简单,只是多了一个优点:单件可以延迟实例化。


加入多线程:

假设这里有两个线程要执行这段代码,这两个线程创建单例对象时,检查getInstance()方法内的操作次序和uniqueInstance的值,会出现实例化两个对象。


处理多线程:

方法一:把getInstance()变为同步(Synchronized)方法

public class Singleton {
private static Singleton uniqueInstance;

private Singleton() {}

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

方法二:使用“急切”创建实例,而不用延迟实例化的做法

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

private Singleton() {}

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

方法三:使用“双重检查加锁”,在getInstance()中减少使用同步

public class Singleton {
private volatile static Singleton uniqueInstance;

private Singleton() {}

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


使用synchronized同步方法对系统性能有一定影响,所以在多线程同步getInstance方法时,将会产生很大的影响。


对比处理多线程的三种方式:

1)同步getInstance()方法:这是保证可行的最直接做法,对于没有性能的考虑,可以使用该方法

2)急切实例化:我们一定会创建该对象的实例,在编译时静态初始化实例

3)双重加锁机制:综合性能上的考虑,检查实例,不存在就进入同步区块,进入同步区块再检查一次,如果是null,才创建实例。保证JDK1.5上版本


volatile关键字确保:当uniqueInstance变量被初始化成Singleton实例时,多个线程正确地处理uniqueInstance变量。





0 0
原创粉丝点击