Android开发设计模式之——单例模式关于线程不安全问题处理
单例模式是设计模式中最常见也最简单的一种设计模式,保证了在程序中只有一个实例存在并且能全局的访问到。比如在Android实际APP 开发中用到的 账号信息对象管理, 数据库对象(SQLiteOpenHelper)等都会用到单例模式。下面针对一些例子分析一下我们在开发过程中应用单例模式需要注意的点。
一、作用
单例模式(Singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点
二、适用场景
1. 应用中某个实例对象需要频繁的被访问。
2. 应用中每次启动只会存在一个实例。如账号系统,数据库系统。
三、常用的使用方式
(1)懒汉式
这是在开发中很容易就能写出来的一种方式,如下
- public class Singleton {
- /* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */
- private static Singleton instance = null;
- /* 私有构造方法,防止被实例化 */
- private Singleton() {
- }
- /* 1:懒汉式,静态工程方法,创建实例 */
- public static Singleton getInstance() {
- if (instance == null) {
- instance = new Singleton();
- }
- return instance;
- }
- }
调用:
- Singleton.getInstance().method();
优点:延迟加载(需要的时候才去加载)
缺点: 线程不安全,在多线程中很容易出现不同步的情况,如在数据库对象进行的频繁读写操作时。
(2)加同步锁
既然线程不安全,那就加上同步锁,一种加法如下:
- /*2.懒汉式变种,解决线程安全问题**/
- public static synchronized Singleton getInstance() {
- if (instance == null) {
- instance = new Singleton();
- }
- return instance;
- }
更一般的写法是这样
- /*加上synchronized,但是每次调用实例时都会加载**/
- public static Singleton getInstance() {
- synchronized (Singleton.class) {
- if (instance == null) {
- instance = new Singleton();
- }
- }
- return instance;
- }
调用:
- Singleton.getInstance().method();
优点:解决了线程不安全的问题。
缺点:效率有点低,每次调用实例都要判断同步锁
补充:在Android源码中使用的该单例方法有:InputMethodManager,AccessibilityManager等都是使用这种单例模式
(3)双重检验锁
要优化(2)中因为每次调用实例都要判断同步锁的问题,很多人都使用下面的一种双重判断校验的办法
- /*3.双重锁定:只在第一次初始化的时候加上同步锁*/
- public static Singleton getInstance() {
- if (instance == null) {
- synchronized (Singleton.class) {
- if (instance == null) {
- instance = new Singleton();
- }
- }
- }
- return instance;
- }
这种方法貌似很完美的解决了上述效率的问题,它或许在并发量不多,安全性不太高的情况能完美运行,但是,这种方法也有不幸的地方。问题就是出现在这句
- instance = new Singleton();
在JVM编译的过程中会出现指令重排的优化过程,这就会导致当 instance实际上还没初始化,就可能被分配了内存空间,也就是说会出现 instance !=null 但是又没初始化的情况,这样就会导致返回的 instance 不完整(可以参考:http://www.360doc.com/content/11/0810/12/1542811_139352888.shtml)。
调用:
- Singleton.getInstance().method();
优点:在并发量不多,安全性不高的情况下或许能很完美运行单例模式
缺点:不同平台编译过程中可能会存在严重安全隐患。
补充:在android图像开源项目Android-Universal-Image-Loader (https://github.com/nostra13/Android-Universal-Image-Loader)中使用的是这种方式。
(4)内部类的实现
内部类是一种好的实现方式,可以推荐使用一下:
- public class SingletonInner {
- /**
- * 内部类实现单例模式
- * 延迟加载,减少内存开销
- *
- * @author xuzhaohu
- *
- */
- private static class SingletonHolder {
- private static SingletonInner instance = new SingletonInner();
- }
- /**
- * 私有的构造函数
- */
- private SingletonInner() {
- }
- public static SingletonInner getInstance() {
- return SingletonHolder.instance;
- }
- protected void method() {
- System.out.println("SingletonInner");
- }
- }
调用:
- SingletonInner.getInstance().method();
优点:延迟加载,线程安全(java中class加载时互斥的),也减少了内存消耗
(5)枚举的方法
这是网上很多人推荐的一种做法,但是貌似使用的不广泛,大家可以试试,
- /**
- * @function:单例模式枚举实现
- * @author xuzhaohu
- *
- */
- public enum SingletonEnum {
- /**
- * 1.从Java1.5开始支持;
- * 2.无偿提供序列化机制;
- * 3.绝对防止多次实例化,即使在面对复杂的序列化或者反射攻击的时候;
- */
- instance;
- private String others;
- SingletonEnum() {
- }
- public void method() {
- System.out.println("SingletonEnum");
- }
- public String getOthers() {
- return others;
- }
- public void setOthers(String others) {
- this.others = others;
- }
- }
调用:
- SingletonEnum.instance.method();
优缺点:如代码中注释。
上面主要讲了单例模式5种创建方法,大家可以根据其优缺点进行个人实际项目中的使用。讲的属于抛砖引玉,大家多提意见。
Android开发设计模式之——单例模式关于线程不安全问题处理的更多相关文章
- Android开发UI之在子线程中更新UI
转自第一行代码-Android Android是不允许在子线程中进行UI操作的.在子线程中去执行耗时操作,然后根据任务的执行结果来更新相应的UI控件,需要用到Android提供的异步消息处理机制. 代 ...
- android 开发设计模式---单例模式
要保证单例,需要做以下几步 必须防止外部可以调用构造函数进行实例化,因此构造函数必须私有化. 必须定义一个静态函数获得该单例 单例使用volatile修饰 使用synchronized 进行同步处理, ...
- Android开发-API指南-进程与线程
Processes and Threads 英文原文:http://developer.android.com/guide/components/processes-and-threads.html ...
- 一天一个设计模式——(Singleton)单例模式(线程安全性)
一.模式说明 有时候,我们希望在应用程序中,仅生成某个类的一个实例,这时候需要用到单例模式. 二.模式类图 三.模式中的角色 Singleton角色,该模式中仅有的一个角色,该角色有一个返回唯一实例的 ...
- android 开发设计模式---Builder模式
我们通过一个例子来引出Builder模式.假设有一个Person类,我们通过该Person类来构建一大批人,这个Person类里有很多属性,最常见的比如name,age,weight,height等等 ...
- android 开发设计模式---Strategy模式
假设我们要出去旅游,而去旅游出行的方式有很多,有步行,有坐火车,有坐飞机等等.而如果不使用任何模式,我们的代码可能就是这样子的. 12345678910111213141516171819202122 ...
- android 开发设计模式---观察者模式
情景1 有一种短信服务,比如天气预报服务,一旦你订阅该服务,你只需按月付费,付完费后,每天一旦有天气信息更新,它就会及时向你发送最新的天气信息. 情景2 杂志的订阅,你只需向邮局订阅杂志,缴纳一定的费 ...
- Android 开发中三种多线程
在开发工程中线程可以帮助我们提高运行速度,Android开发中我知道的线程有四个一个是老生长谈的Thread,第二个是asyncTask,第三个:TimetTask,第四个是Looper,四个多线程各 ...
- Android开发中常见的设计模式
对于开发人员来说,设计模式有时候就是一道坎,但是设计模式又非常有用,过了这道坎,它可以让你水平提高一个档次.而在android开发中,必要的了解一些设计模式又是非常有必要的.对于想系统的学习设计模式的 ...
随机推荐
- Oracle 11gR2中启动Scott用户的方法
Oracle 中启动 Scott 用户 的方法 , 在 Oracle11gR2, (g 代表‘网络’的意思) 数据库中 Scott 这个用户 安装时是被锁定的,安装 Oracle的时候 ,你可以直接选 ...
- js 表单操作
order.aspx 订单页- order-detail.aspx订单确认页- 操作:order.aspx提交订单@1,跳转到order-detail.aspx页面,确认页面操作:返回上一步@2- ...
- [theWord] 一种英文字典的基类设计
theWord --- 一种英文字典的基类设计 使用场景 想写一个应用,来记录自己背单词时候,对每个单词的记忆状况之类的东西.至于为什么做这个,试过了一些背单词软件,并不觉得好用,自己做一个吧. 那么 ...
- Codeforces Round #370 (Div. 2) B
Description Memory is performing a walk on the two-dimensional plane, starting at the origin. He is ...
- 推荐一款非常棒的谷歌插件---快速查看HTML页面元素的CSS样式
一.下载地址 http://chromecj.com/web-development/2015-05/456/download.html 二.简介 CssViewer是一款快速查看当前页面元素的CSS ...
- HDU 5059 Harry And Biological Teacher
链接:http://acm.hdu.edu.cn/showproblem.php?pid=5069 题意:给出n个串,m个询问,每个询问(u,v),求u的一个最长后缀是v的前缀. 思路:离线.将关于u ...
- Windows平台安装Redmine2.5.x
安装准备 下载RubyInstaller和Development Kit,也可以使用RailsFTW,轻松搞定windows下的安装. 下载MySql 下载mysql-connector-c-noin ...
- 1,linux基础知识以及新建虚拟机
1,Windows图形界面只是在个人电脑上普及(dos界面):lunix是在服务器领域,服务器上绝对不出现图形化界面(命令行). 2,2.6.18 主板本,次版本,末版本 如果末版本积累到一定程序就 ...
- [SAP ABAP开发技术总结]字段符号FIELD-SYMBOLS
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- C# 线程(五):线程池
From : http://kb.cnblogs.com/page/42531/ 在多线程的程序中,经常会出现两种情况: 一种情况: 应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然 ...