【设计模式】——五问单例模式
2016-04-09 21:35
302 查看
0.什么是单例模式?单例模式确保一个类只有一个实例,并提供一个全局访问点。1.什么情况下使用单例模式?当你需要确保程序中的一个类最多只有一个实例时。2.如何实现单例模式?①懒汉式:适用于对性能要求不高的情况。(不推荐)缺点在于,第一次加载要初始化,反应比较慢;每一次调用这个方法都需要同步,太过累赘。http://www.hollischuang.com/archives/197⑥使用容器实现单例模式http://stormzhang.com/designpattern/2016/04/04/singleton-extend/让我们来破坏单例模式/article/9025803.html《Android源码设计模式解析与实战》《HeadFirst设计模式》
publicclassSingleton{
privatestaticSingletonuniqueInstance;
//其他有用的实例化的变量,synchronized关键字确保不会有两个线程同时进入这个方法
publicstaticsynchronizedSingletongetInstance(){
if(uniqueInstance==null){
uniqueInstance=newSingleton();
}
returnuniqueInstance;
//其他有用的方法
}②饿汉式:适用于经常创建并使用单例,或是在创建和运行时方面的负担不太繁重时。(推荐)
publicclassSingleton{
//在静态初始化器(staticinitialize)中创建单例,这段代码保证了线程安全
privatestaticSingletonuniqueInstance=newSingleton();
//私有的构造器
privateSingleton(){}
publicstaticSingletongetInstance(){
//已经有实例,可以直接使用
returnuniqueInstance;
}
}③双重检查加锁(不推荐)首先检查实例是否已经创建,在没有创建的情况下才进行同步:即只有第一次会同步。请注意,双重加锁检查不适用于1.4及更早版本的java,可能会出现失效。
publicclassSingleton{//volatile关键词确保多个线程能正确处理uniqueInstance变量
privatevolatilestaticSingletonuniqueInstance;
privateSingleton(){}
publicstaticSingletongetInsatance(){//先检查实例是否存在,不存在才进入同步区块
if(uniqueInstance==null){//避免不必要的同步
synchronized(Singleton.class){
if(uniqueInstancen==null){
uniqueInstance=newSingleton();
}
}
}
returnuniqueInstance;
}
}④静态内部类(推荐)
publicclassSingleton{
privateSingleton(){}
publicstaticSingletongetInstance(){
returnSingletonHolder.sInstance;
}
/**
*静态内部类
*/
privatestaticclassSingletonHolder{
privatestaticfinalSingletonsInstance=newSingleton();
}
}第一次加载Singleton类时并不会初始化sInstance,只有在第一次调用Singleton的getInstance方法才会导致sInstance被初始化,技能保证线程安全,也能保证单例对象唯一,是非常推荐的实现方式。⑤枚举单例优点:线程安全、任何情况下都是一个单例。不仅能有字段也能有自己的方法。【枚举不受反序列化的影响。】
publicenmuSingletonEnum{
INSTANCE;
publicvoiddoSomething(){
System.out.println("dosth");
}
}其他实例中如果要防止单例对象在被反序列化时重新生成对象,需要加入以下方法:
privateObjectreadResolve()throwObjectStreamException{
returnsInstance;
}另外反射也是可以破坏单例的:
importjava.lang.reflect.Constructor;
publicclassSingleton{
publicstaticfinalSingletonINSTANCE=newSingleton();
privateSingleton(){
}
publicSingletongetInstance(){
returnINSTANCE;
}
publicstaticvoidmain(String[]args)throwsException{
//反射机制破坏单例模式
Classclazz=Singleton.class;
Constructorc=clazz.getDeclaredConstructor();
//反射机制使得private方法可以被访问!!!
c.setAccessible(true);
//判断反射生成的对象与单例对象是否相等
System.out.println(Singleton.INSTANCE==c.newInstance());
}
}而枚举能解决这两个问题。而枚举不好的一点就在于:枚举类内存占用上是静态变量的两倍以上,所以在Android中要尽可能的避免这种写法如果你的程序不是大量采用枚举,那么这种性能的体现是很小的,基本不会受到影响,不用特别在意。当然如果你的App出现了性能问题,理论上这个地方就是一个可以优化的性能优化点。、关于枚举是如何优化的:
publicclassSingletonManager{
privatestaticMap<String,Object>objMap=newHashMap<String,Object>();
privateSingletonManager(){}
publicstaticvoidregisterService(Stringkey,Objectinstance){
if(!objMap.containsKey(key)){
objMap.put(key,instance);
}
}
publicstaticObjectgetService(Stringkey){
returnobjMap.get(key);
}
}将多种单例类型注入到一个统一的管理类中,在使用时根据key获取对象对应类型的对象。这种方式使得我们可以管理多种类型的单例,并且在使用时可以通过统一的接口进行获取操作,降低了用户的使用成本,也对用户隐藏了具体实现,降低了耦合度。最后,不管采取何种方案,请时刻牢记单例的三大要点:线程安全延迟加载序列化与反序列化安全3.单例模式能否继承构造器是私有的,不能用私有构造器来扩展类,如果把构造器改成public或是protected就不能算是真正的”单例“了。4.全局变量和单例模式的比较全局变量可以提供全局访问,但是不能保证只有一个实例。这就是全局变量的局限性。参考资料:单例模式的一些注意点
相关文章推荐
- 软件工程结对作业02
- LINUX内核分析第七周学习总结:可执行程序的装载
- 【转】Java中的static关键字解析
- Eclipse配置Struts2问题:ClassNotFoundException: org...dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
- 拷贝文件
- <css 九>margin
- Apktool的使用
- 教你正确地利用Netty建立连接池
- IEjs 调试、火狐 js 调试
- 一个数组实现两个栈
- Markdown 简明语法手册
- 俄罗斯方块类的实现以及方块在画布中显示
- Hibernate 关联映射之---- 多对多双向映射
- Android 开源框架介绍序列表
- 设置stm32系统各部分时钟
- 通过例子学习 Keystone - 每天5分钟玩转 OpenStack(19)
- jsp中radio的性别信息的数据回显
- Java 浅谈输入输出流
- 剑指Offer--005-从尾到头打印链表
- 第一次启动APP,欢迎页出现一次