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开发中,必要的了解一些设计模式又是非常有必要的.对于想系统的学习设计模式的 ...
随机推荐
- 【转】MYSQL入门学习之五:MYSQL的字符集
转载地址:http://www.2cto.com/database/201212/175541.html MySQL的字符集支持(Character Set Support)有两个方面:字符集(Cha ...
- Google Analytics Premium VS Adobe Analytics
在很久以前的互联网年代,Google收购了一家名为Urchin的公司,进而演化诞生了Google Analytics.当Goochin(Google / Urchin)首次亮相时,它被所有人称为“新的 ...
- JAVA基础知识之IO——对象序列化
对象序列化 Java对象序列化(Serialize)是指将Java对象写入IO流,反序列化(Deserilize)则是从IO流中恢复该Java对象. 对象序列化将程序运行时内存中的对象以字节码的方式保 ...
- 单片机C语言开发学习笔记---动态的数码管
在郭天祥的那本书中,有一个通过按键控制数码管的例子,在运行这个例子的时候,我发现当按键按下的时候,第一位数码管会熄掉,这是为什么呢? 后来在网上找到了原因,当我按下按键不松开的时候,接下来要运行的代码 ...
- 浅谈Apache性能调优
做了很多WEB系统性能测试,都知道了解测试环境,服务器硬件配置,web服务器参数配置是我们开始测试前首先要做的事情. 针对并发数量来说,不同数量级的用户并发,需求的服务器和web服务参数肯定是不同的. ...
- 2016年12月16日 星期五 --出埃及记 Exodus 21:11
2016年12月16日 星期五 --出埃及记 Exodus 21:11 If he does not provide her with these three things, she is to go ...
- iosanimationWithKeyPath
animationWithKeyPath的值: transform.scale = 比例轉換 transform.scale.x = 闊的比例轉換 transform.scale.y ...
- winform 发邮件
System.Net.Mail.SmtpClient client = new SmtpClient("smtp.163.com"); client.UseDefaultCre ...
- 深入理解C语言中的指针与数组之指针篇
转载于http://blog.csdn.net/hinyunsin/article/details/6662851 前言 其实很早就想要写一篇关于指针和数组的文章,毕竟可以认为这是C语言的根本 ...
- CTabCtrl的使用
1.在主窗口中定义一个CtabCtrl,添加变量m_tabctrl; 2.添加两个子窗口IDD_ONE_DIALOG,IDD_TWO_DIALOG(新建对话框,然后双击界面添加头文件和cpp),属性为 ...