什么是单例模式

所谓单例模式,就是确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例的设计模式。单例模式是最简单的设计模式,也是应用最广的设计模式。一般用于避免产生多个对象消耗过多的资源或者某种类型的对象必须独一无二的情景。

单例模式的实现方式

(1)饿汉式

单例模式极其简单,仅有一个单例类。既然常用于确保某种类型的对象必须独一无二的情景,那么我们可以用皇帝来举例。代码如下:public classEmperor {//初始化一个皇帝,国不可一日无君private static finalEmperoremperor=newEmperor();//防止刁民冒充皇帝privateEmperor(){}public staticEmperor getEmperor(){returnemperor;

}

}

从上述代码中可以看到,类不能通过new的形式构造对象,只能用方法来获取唯一的静态对象。这种在声明的时候就初始化的实现方式就叫做饿汉式。

(2)懒汉式

与饿汉式不同,懒汉式只有在第一次调用方式时才进行初始化。实现代码如下:public classSingleton {private staticSingletoninstance;privateSingleton(){}public static synchronizedSingleton getInstance(){if(instance==null){instance=newSingleton();

}returninstance;

}

}

懒汉式在方法中添加了synchronized关键字,可以在多线程情况下确保单例对象独一无二。但即使已经被初始化,每次调用还会进行同步,会消耗不必要的资源,并且第一次加载时进行实例化会拖慢反应速度,因此懒汉式一般不建议使用。但懒汉式并非一无是处,如果一直没有人用的话,就不会创建实例,则是节约空间。这是以时间换空间的实现方式,与饿汉式的以空间换时间各有所长。

还记得语文老师讲课外文学知识题的“禅杖就是鲁智深,戒刀就是武松,板斧就是李逵”的规律吗?注意上面代码的getIntance()方法,实战中见到getIntance()就是单例模式的准确率八九不离十。

(3)DCL式

Double Check Lock(以下简称DLC)实现单例模式既能够在需要时才初始化对象,又能保证线程安全。代码如下:public classSingleton {private staticSingletoninstance;privateSingleton(){}public staticSingleton getInstance(){if(instance==null){synchronized(Singleton.class){if(instance==null){instance=newSingleton();

}

}

}returninstance;

}

}

DCL可以保证无论何时读取这个变量,都是读到内存中最新的值,无论何时写这个变量,都可以立即写到内存中。DCL是目前单例模式最常见的实现方式。

(4)静态内部类式

DCL尽管能完美解决资源消耗、同步多余、线程不安全的问题,却有低概率在并发场景比较复杂的情况下失效(少见于J2EE和Hadoop等场景,绝少见于Android场景)。因此在对性能要求极高的情况下我们可以采取静态内部类式来实现单例模式。代码如下:public classSingleton {privateSingleton(){}public staticSingleton getInstance(){returnSingletonHolder.instance;

}private static classSingletonHolder{private static finalSingletoninstance=newSingleton();

}

}

静态内部类式利用ClassLoader机制来保证初始化时仅有一个线程,不但不会造成性能损耗,还是天衣无缝的安全方式。

(5)单例模式的容器式管理

还是拿皇帝举例子,天下可能有多个皇帝,一个软件也可能有多个单例对象。举唐玄宗李隆基和大燕皇帝安禄山的对立的例子不是太恰当,毕竟几乎没有史书认同安禄山是合法皇帝。我就举一个大家耳熟能详的例子——《三国演义》第80回讲述了中国历史上第一次同时存在两位被后世的历史学家认定为合法皇帝(曹丕和刘备)的局面,也是最著名的一次。我们先建立一个管理类:public classEmperorManager {public static finalStringWEI="魏";public static finalStringSHU="蜀";public static finalStringWU="吴";private staticMapemperors=newHashMap<>();privateEmperorManager(){}public static voidascendEmperor(String key,Object emperor){if(!emperors.containsKey(key)){emperors.put(key,emperor);

}

}public staticObject getEmperor(String key){returnemperors.get(key);

}

}

然后就可以管理多个单例对象了://曹丕废帝篡炎刘EmperorManager.ascendEmperor(EmperorManager.WEI,WeiEmperor.getEmperor());//汉王正位续大统EmperorManager.ascendEmperor(EmperorManager.SHU,ShuEmperor.getEmperor());

几年后,孙权登基,天下又有了新的皇帝,写法以此类推。

Android源码中的单例模式

(1)Application

Application是Android中最典型,也是最常见的单例模式。用户重写Application类也只重写一个。

(2)Activity

Activity在singleInstance启动模式下只有一个实例,并且这个实例独立运行在一个Task中,不允许有别的Activity存在,这也是一种单例模式。

(3)Service

Service用bindService()启动之后,无论再启动多少次,都只会调用onStartCommand()而不会再调用onCreate(),因为每次调用的Service都是同一对象。

(4)各种Manager

Android中有很多管理类,比如WindowManager、PowerManager、SensorManager、ActivityManager、StorageManager以及ServiceManager等等,这些管理类分别对某些资源进行操作,为了避免对同一资源的同时操作,也为了节约资源,都采取了单例模式。

(5)UID

在Picasso和Glide等框架流行起来之前,最常见的图片加载框架非Universal-Image-Loader(以下简称UID)莫属,UID的初始化方式如下://全局初始化此配置ImageLoader.getInstance().init(config);

这里又见到了熟悉的getIntance(),根据思维定式判定这是单例模式。

Android开发中如何利用单例模式

(1)当创建一个对象需要较多资源时,比如读取配置或依赖较多其他对象时,可以用创建一个单例对象常驻内存的方式解决这个问题。

(2)当一个对象需要经常调用所以需要反复创建、销毁时,为了减少内存开支,可以用单例模式来减少创建、销毁该对象的资源浪费。

(3)当需要对同一个资源进行操作时(例如File I/O),可以创建一个FileManager,这样内存里只有一个实例,避免了对同一个资源的同时操作。

需要注意的几个问题

(1)单例模式必然有static修饰符,如果持有Activity的Context,很容易造成OOM,因此尽量使用Application的Context;此外有多少初学者在Activity销毁时忘记销毁视频或地图的单例对象而吃了大亏?

(2)在不需要独一无二的对象的时候不要采用单例模式,譬如自定义控件就是最不适合单例模式的场景。

本系列其他博客

android 单例销毁,【设计模式与Android】单例模式——独一无二的皇帝相关推荐

  1. java设计模式 单例_java设计模式一(单例模式singleton)

    1 概述 如果要保证系统里一个类最多只能存在一个实例时,我们就需要单例模式.这种情况在我们应用中经常碰到,例如缓存池.数据库连接池.线程池.一些应用服务实例等.在多线程环境中为了保证实例的唯一性其实并 ...

  2. 单例销毁_【PHP设计模式】单例模式

    前言 设计模式是我们开发过程中的重中之重,所以今天小编就来学习设计模式中的单例模式. 单例模式 <?phpclass Singleton { /*** 定义一个静态变量保存已经实例化的对象* * ...

  3. android 单例的作用,Android中单例模式的几个坑

    先来看这样一个单例,稍微有点经验的同学可能都会说,这样的单例是非线程安全的.要加个volatile关键字才可以.class Singleton{        private static  Sing ...

  4. 单例销毁_TypeScript 设计模式之单例模式

    一.简介 单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池.全局缓存.浏览器中的 window 对象等.单例模式用于保证一个类仅有一个实例,并提供一个访问它的全局访问点. 二.优缺点 ...

  5. java connection 单例_Java设计模式之单例模式详解

    Java设计模式之单例模式详解 什么是设计模式 设计模式是在大量的实践中总结和理论之后优选的代码结构,编程风格,以及解决问题的思考方式.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可 ...

  6. java设计模式 单例_java设计模式--单例模式

    单例设计模式 Singleton是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点. 核心知识点如下: (1) 将采用单例 ...

  7. android 单例存储,Android 单例在内存中存储数据

    开发中我们有时候需要在APP运行中存储一些数据,存储在内存中,这时候创建一个单例就非常方便,我只做为笔记发布,大家随意看看 public class Singleton { //单例模式实例 priv ...

  8. 单例 (Singleton)设计模式

    所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法.如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构 ...

  9. java 线程安全的单例_线程安全的单例模式的几种实现

    单例模式是常见的设计模式之一:目的是节省内存,限制了实例的个数:有利于java GC回收机制. 单例模式的三个好处: 1.控制资源的使用,通过线程同步来控制资源的并发访问 2.控制实例的产生个数,来达 ...

最新文章

  1. Python 2x 中list 里面的中文打印效果乱码
  2. DPDK 报文收发流程(二十五)
  3. [2019BUAA软件工程]第1次阅读作业
  4. Nexys3学习手记1:写在前面的话
  5. java创建activity视图_java-动态创建的视图id始终为null-findviewbyid不起作用
  6. python 多个列表合并_Python实现合并两个列表的方法分析
  7. 基于XMPP协议的Android即时通信系
  8. 飞思卡尔9S12X系列双核中的协处理器XGATE使用方法
  9. RapidMiner 数据转换
  10. Fedora:使用Fedora 28在Firefox上启用h264视频(搜狐/优酷视频)
  11. AWS、Azure、谷歌云、阿里云最新全方位比较
  12. Elasticsearch深入理解(九)——三种分页方式选取
  13. python 监听键盘输入并收集数据进行分析
  14. English 动词篇
  15. Linux报错: terminate called after throwing an instanc
  16. 君子剑,怎样炼成?——再再谈岳不群
  17. 服务器操作系统该选 Debian/Ubuntu 还是 CentOS?
  18. YTUOJ-HOMEWORK
  19. Python 的日志模板
  20. “无实物尝百味”通过控制微电流刺激产生味觉—3.复位配网和电量报警实现篇

热门文章

  1. 将纯数字转成货币单位(万,亿,兆)
  2. JAVA日志MDC追踪快速定位问题源头
  3. 如何从三星恢复已删除的照片?
  4. 0x0d和0x0a 学习
  5. 使用 HSV 颜色模型和 openCV 构建昼夜分类器
  6. JavaScript原型和原型链(详细解读)
  7. 牛顿问题(牛吃草问题)-python题解
  8. RedisTemplate实现Redis锁
  9. RDP时提示CredSSP加密问题
  10. 设置浏览器代理服务器