设计模式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变量。
单件模式:单件模式确保一个类只有一个实例,并提供一个全局访问点。
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变量。
相关文章推荐
- Python3写爬虫(四)多线程实现数据爬取
- PropertyChangeListener简单理解
- 什么是设计模式
- 设计模式之创建型模式 - 特别的变量问题
- 七、设计模式——装饰模式
- 设计模式总结
- 设计模式之创建型模式
- 浅谈设计模式的学习
- C#实现多线程的同步方法实例分析
- 浅谈chuck-lua中的多线程
- C#简单多线程同步和优先权用法实例
- C#多线程学习之(四)使用线程池进行多线程的自动管理
- C#多线程编程中的锁系统(三)
- C#多线程学习之(六)互斥对象用法实例
- 基于一个应用程序多线程误用的分析详解
- C#多线程学习之(三)生产者和消费者用法分析
- C#多线程学习之(一)多线程的相关概念分析
- C#多线程之Thread中Thread.IsAlive属性用法分析
- C#多线程编程之使用ReaderWriterLock类实现多用户读与单用户写同步的方法
- C#控制台下测试多线程的方法