设计模式的应用场景(5)--单例模式
2017-08-28 20:00
274 查看
单例模式
定义:单例模式确保一个类只有一个实例并且该实例必须自动创建,具有唯一的全局访问点。优点:客户端智能通过一个公共的调用点对类实例进行调用。
缺点:实现单例模式的类不能被别的类继承。
使用时机:当系统要求一个类只有一个实例时候。
单例模式在程序设计中使用的频率非常之高,其设计的目的是为了在程序中提供唯一一个对象(保证只被构造一次),例如写入日志的log对象,windows的任务管理器实现(只能打开一个)。这里主要介绍单例模式使用Java的实现(包括饿汉式及懒汉式)。
实现
这里使用Log类作为例子,Log对象需要在程序中只有一个对象且只初始化一次。
饿汉式
饿汉式的单例模式理解起来是比较容易的,就是在单例类加载的时候就初始化需要单例的对象。实现也比较容易。
public class Singleton{ private static Log logObj = new Log(); public static Log getInstance(){ return logObj; } }
懒汉式
如果logObj需要占用很大的内存,如果一开始就初始化logObj,那么会占用大量的内存。此时,有人就想,如果我在想用的时候再初始化Log类的对象,像懒汉一样,只有用到的时候再初始化,需要怎么设计呢?
实现一(非线程安全版本)
public class Singleton{ private static Log logObj = null; public static Log getInstance(){ if(logObj == null){ logObj = new Log(); } return logObj; } }
实现二(线程安全版本)
public class Singleton{ private static Log logObj = null; public static synchronized Log getInstance(){ if(logObj == null){ logObj = new Log(); } return logObj; } }
为了实现线程安全,这个版本的实现牺牲了一定的效率,如果logObj已经初始化,那么其他线程还需要同步的进入getInstance方法,会造成效率的损失。于是,有些人实现了下面的版本。
实现三(错误版本)
public class Singleton{ private static Log logObj = null; public static Log getInstance(){ if(logObj == null){ synchronized(Singleton.class){ if(logObj == null){ logObj = new Log(); } } } return logObj; } }
乍看起来上面的版本是没问题的,如果某个线程A发现logObj 还没初始化,那么就进入同步块初始化logObj,如果在这期间有其他线程B进入,那么线程B就会等待进入同步块,等待A 线程退出同步块,logObj 已经初始化了,B 线程进入同步块后发现logObj 不为null,退出同步块,不再初始化logObj 。 这样既实现了线程安全,又兼顾了效率,确实是很聪明的编码方式。但是问题来了,由于指令重排序的存在,会导致Log在完全初始化之前logObj就已经不为null
afeb
。这样其他线程可能会得到未完全初始化的对象。
解决方法
JDK1.5版本后扩展了volitile语义,可以保证上述代码的正确性,为此只要将logObj 声明为volitile即可(volitile之前只是保证内存的可见性而已)。
使用静态内部类。
加载一个类时,其内部类不会同时被加载。一个类被加载,当且仅当其某个静态成员(静态域、构造器、静态方法等)被调用时发生。
并且jvm会保证类加载的线程安全问题,所以利用这个特性可以写出兼顾效率与保证线程安全的版本。
实现四(兼顾效率与线程安全的版本)
public class Singleton{ static class LogHolder{ static Log logObj = new Log(); } public static Log getInstance(){ return LogHolder.logObj; } }
这样在Singleton类加载时,并不会加载LogHolder,也就不会初始化Log,如果有线程访问getInstance方法,那么jvm会首先加载LogHolder类,并保证初始化logObj,最后返回logObj。
相关文章推荐
- Java设计模式之《桥接模式》及应用场景
- 常见的六种设计模式以及应用场景
- C++技术问题总结-第14篇 常用设计模式及其应用场景
- 写出你所知道的设计模式和应用场景
- 设计模式--6大原则应用场景通俗版(1)
- 设计模式 单例模式的缺陷和补救办法及应用场景2
- 常用设计模式之应用场景/好处在哪儿
- 设计模式的应用场景(9)--装饰模式
- 总结23中设计模式应用场景
- 设计模式应用场景举例
- 设计模式的应用场景(22)--迭代器模式
- Java设计模式之《单例模式》及应用场景
- Java设计模式之《适配器模式》及应用场景
- 常见设计模式的应用场景
- php常用几种设计模式的应用场景
- 设计模式的应用场景(1)--分类和原则
- Java设计模式之《适配器模式》及应用场景
- ACE中的设计模式应用场景
- 大家一起来说一说自己掌握的设计模式和在工作中的应用场景,分享经验
- 转:23种设计模式的应用场景