您的位置:首页 > 其它

设计模式5—单件模式

2015-11-25 20:26 190 查看
有些对象只需要一个,创建独一无二的实例,比如说:线程池(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变量。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息