设计模式之单例模式
2014-04-29 15:06
274 查看
保证系统里面的类最多只能有一个实例对象。简单单例模式的实现:a.首先定义一个私有的变量instance来实例化类对象;b.将构造方法私有化;c.实现全局访问点public static Singleton getInstance()方法,而由于该方法是私有的,因此变量instance也要被定义为私有的。d.如果实例需要比较复杂的实例化过程,那么就将实例化过程放在static{}中:
懒汉式:
此实现是线程安全的,多个线程进行访问时不会实例化多个对象,因为static属性只会被初始化一次,缺点是无论是否用到该实例都会被初始化,无故的开销变大。
饿汉式:
这个实现保证了只有在调用该类的时候对象才被初始化(延迟创建),但是缺点是线程不安全,当多个线程同时访问的时候,极可能实例化出多个对象。
解决:给整个方法添加同步
(public static synchronized Singleton getInstance())
,但这样是解决了线程的安全问题,却大大降低了性能。确实有些不必要的同步,例如返回操作,其实真正需要同步的就是创建的时候,改进:
s private volatile static Singleton instance = null;
//实例对象用volatile修饰,volatile具有synchronized可见性;这样线程就能自动发现volatile变量的最新值,这样有一个线程实例化成功,其他线程就能立即发现。
这个其实就叫(double-cheched-locking模式)
这样还是有一个缺点就是:就是在一个线程还未完全初始化该对象时,而那个变量已经显示为被初始化,那么其他线程可能去使用这个未被完全初始化的实例,造成系统的崩溃。不过这个在java5以上可以安全运行。
另外一种完美实现的实现既线程安全又延迟加载的模式(Initialization on demand holder)使用静态内部类 示例:
这样就能保证在第一次调用getInstance()方法时,才会去初始化instance实例,而且该实例被定义为static,只会被初始化一次。
接下去还有一个问题就是单例化类的序列化问题:如果单例类实现了serializable接口,这是要特别注意以为在默认情况下,每次反序列化时总会创建一个新的对象,注意系统就会出现多个对象了。解决方法:根据序列化可知:每次反序列化完成前都会去调用readResolve()方法,那就在该方法中,将用原对象取代新创建出来的对象。在是在该实现了序列化的类中再定义一个方法:
Public Singleton readResolve(){
sReturn instance; // instance是唯一的实例对象
}
懒汉式:
public class Singleton{ private static Singleton instance = new Singleton();//定义实例变量 private Singleton(){}; //私有化构造方法 public static Singleton getInstance(){ return instance; } }
此实现是线程安全的,多个线程进行访问时不会实例化多个对象,因为static属性只会被初始化一次,缺点是无论是否用到该实例都会被初始化,无故的开销变大。
饿汉式:
public class Singleton{ private static Singleton instance = null; private Singleton(){}; public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } }
这个实现保证了只有在调用该类的时候对象才被初始化(延迟创建),但是缺点是线程不安全,当多个线程同时访问的时候,极可能实例化出多个对象。
解决:给整个方法添加同步
(public static synchronized Singleton getInstance())
,但这样是解决了线程的安全问题,却大大降低了性能。确实有些不必要的同步,例如返回操作,其实真正需要同步的就是创建的时候,改进:
s private volatile static Singleton instance = null;
//实例对象用volatile修饰,volatile具有synchronized可见性;这样线程就能自动发现volatile变量的最新值,这样有一个线程实例化成功,其他线程就能立即发现。
public static Singleton getInstance(){ if(instance == null){ //如果没有创建就进行同步创建 synchronized(Singleton.class){ if(instance == null){ //再次判断,以防两个线程同时经过第一道判断,之后先后进入同步后还是能创建各自的对象的,故需再次判断 instance = new Singleton(); } } } return instance; }
这个其实就叫(double-cheched-locking模式)
这样还是有一个缺点就是:就是在一个线程还未完全初始化该对象时,而那个变量已经显示为被初始化,那么其他线程可能去使用这个未被完全初始化的实例,造成系统的崩溃。不过这个在java5以上可以安全运行。
另外一种完美实现的实现既线程安全又延迟加载的模式(Initialization on demand holder)使用静态内部类 示例:
Public class Singleton{ Private Singleton(){}; Public static class Singleton1{ Private static final Singleton instance = new Singleton(); } Public static Singleton getInstance(){ Return Singleton1.instance; } }
这样就能保证在第一次调用getInstance()方法时,才会去初始化instance实例,而且该实例被定义为static,只会被初始化一次。
接下去还有一个问题就是单例化类的序列化问题:如果单例类实现了serializable接口,这是要特别注意以为在默认情况下,每次反序列化时总会创建一个新的对象,注意系统就会出现多个对象了。解决方法:根据序列化可知:每次反序列化完成前都会去调用readResolve()方法,那就在该方法中,将用原对象取代新创建出来的对象。在是在该实现了序列化的类中再定义一个方法:
Public Singleton readResolve(){
sReturn instance; // instance是唯一的实例对象
}
相关文章推荐
- js验证日期格式的函数
- MyEclipse创建hibernate
- openstack, kvm, qemu-kvm以及libvirt之关系
- POJ 3348 Cows
- 本地存储(localStorage、sessionStorage、web Database)
- 计算CPU 百分比 - 基于openstack kvm 虚拟机采集片段代码分享
- DispatcherServlet与初始化主线---SpringMVC(4)
- ExtJS 之store(转)
- Android开发详解之onTouch和onClick详解
- PythonChallenge闯关游戏——第1-5关
- 使用数据绑定展示数据的局限性
- Timus 1119. Metro 动态规划
- Android ListView 几个重要属性
- char*,string,float,int 转换
- servlet
- C#函数式程序设计之泛型
- 简单数据库数据导出工具总结笔记
- JavaScript eval()
- [Android]Android 颜色大全 colors.xml
- SpringMVC深度探险(二) —— SpringMVC概览