单例模式是设计模式中最常见也最简单的一种设计模式,保证了在程序中只有一个实例存在并且能全局的访问到。比如在Android实际APP 开发中用到的 账号信息对象管理, 数据库对象(SQLiteOpenHelper)等都会用到单例模式。下面针对一些例子分析一下我们在开发过程中应用单例模式需要注意的点。

一、作用
单例模式(Singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点

二、适用场景

1. 应用中某个实例对象需要频繁的被访问。

2. 应用中每次启动只会存在一个实例。如账号系统,数据库系统。

三、常用的使用方式

(1)懒汉式

这是在开发中很容易就能写出来的一种方式,如下

  1. public class Singleton {
  2. /* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */
  3. private static Singleton instance = null;
  4. /* 私有构造方法,防止被实例化 */
  5. private Singleton() {
  6. }
  7. /* 1:懒汉式,静态工程方法,创建实例 */
  8. public static Singleton getInstance() {
  9. if (instance == null) {
  10. instance = new Singleton();
  11. }
  12. return instance;
  13. }
  14. }

调用:

  1. Singleton.getInstance().method();

优点:延迟加载(需要的时候才去加载)

缺点: 线程不安全,在多线程中很容易出现不同步的情况,如在数据库对象进行的频繁读写操作时。

(2)加同步锁

既然线程不安全,那就加上同步锁,一种加法如下:

  1. /*2.懒汉式变种,解决线程安全问题**/
  2. public static synchronized Singleton getInstance() {
  3. if (instance == null) {
  4. instance = new Singleton();
  5. }
  6. return instance;
  7. }

更一般的写法是这样

  1. /*加上synchronized,但是每次调用实例时都会加载**/
  2. public static Singleton getInstance() {
  3. synchronized (Singleton.class) {
  4. if (instance == null) {
  5. instance = new Singleton();
  6. }
  7. }
  8. return instance;
  9. }

调用:

  1. Singleton.getInstance().method();

优点:解决了线程不安全的问题。

缺点:效率有点低,每次调用实例都要判断同步锁

补充:在Android源码中使用的该单例方法有:InputMethodManager,AccessibilityManager等都是使用这种单例模式

(3)双重检验锁

要优化(2)中因为每次调用实例都要判断同步锁的问题,很多人都使用下面的一种双重判断校验的办法

  1. /*3.双重锁定:只在第一次初始化的时候加上同步锁*/
  2. public static Singleton getInstance() {
  3. if (instance == null) {
  4. synchronized (Singleton.class) {
  5. if (instance == null) {
  6. instance = new Singleton();
  7. }
  8. }
  9. }
  10. return instance;
  11. }

这种方法貌似很完美的解决了上述效率的问题,它或许在并发量不多,安全性不太高的情况能完美运行,但是,这种方法也有不幸的地方。问题就是出现在这句

  1. instance = new Singleton();

在JVM编译的过程中会出现指令重排的优化过程,这就会导致当 instance实际上还没初始化,就可能被分配了内存空间,也就是说会出现 instance !=null 但是又没初始化的情况,这样就会导致返回的 instance 不完整(可以参考:http://www.360doc.com/content/11/0810/12/1542811_139352888.shtml)。

调用:

  1. Singleton.getInstance().method();

优点:在并发量不多,安全性不高的情况下或许能很完美运行单例模式

缺点:不同平台编译过程中可能会存在严重安全隐患。

补充:在android图像开源项目Android-Universal-Image-Loader https://github.com/nostra13/Android-Universal-Image-Loader中使用的是这种方式

(4)内部类的实现

内部类是一种好的实现方式,可以推荐使用一下:

  1. public class SingletonInner {
  2. /**
  3. * 内部类实现单例模式
  4. * 延迟加载,减少内存开销
  5. *
  6. * @author xuzhaohu
  7. *
  8. */
  9. private static class SingletonHolder {
  10. private static SingletonInner instance = new SingletonInner();
  11. }
  12. /**
  13. * 私有的构造函数
  14. */
  15. private SingletonInner() {
  16. }
  17. public static SingletonInner getInstance() {
  18. return SingletonHolder.instance;
  19. }
  20. protected void method() {
  21. System.out.println("SingletonInner");
  22. }
  23. }

调用:

  1. SingletonInner.getInstance().method();

优点:延迟加载,线程安全(java中class加载时互斥的),也减少了内存消耗

(5)枚举的方法

这是网上很多人推荐的一种做法,但是貌似使用的不广泛,大家可以试试,

  1. /**
  2. * @function:单例模式枚举实现
  3. * @author xuzhaohu
  4. *
  5. */
  6. public enum SingletonEnum {
  7. /**
  8. * 1.从Java1.5开始支持;
  9. * 2.无偿提供序列化机制;
  10. * 3.绝对防止多次实例化,即使在面对复杂的序列化或者反射攻击的时候;
  11. */
  12. instance;
  13. private String others;
  14. SingletonEnum() {
  15. }
  16. public void method() {
  17. System.out.println("SingletonEnum");
  18. }
  19. public String getOthers() {
  20. return others;
  21. }
  22. public void setOthers(String others) {
  23. this.others = others;
  24. }
  25. }

调用:

  1. SingletonEnum.instance.method();

优缺点:如代码中注释。

上面主要讲了单例模式5种创建方法,大家可以根据其优缺点进行个人实际项目中的使用。讲的属于抛砖引玉,大家多提意见。

Android开发设计模式之——单例模式关于线程不安全问题处理的更多相关文章

  1. Android开发UI之在子线程中更新UI

    转自第一行代码-Android Android是不允许在子线程中进行UI操作的.在子线程中去执行耗时操作,然后根据任务的执行结果来更新相应的UI控件,需要用到Android提供的异步消息处理机制. 代 ...

  2. android 开发设计模式---单例模式

    要保证单例,需要做以下几步 必须防止外部可以调用构造函数进行实例化,因此构造函数必须私有化. 必须定义一个静态函数获得该单例 单例使用volatile修饰 使用synchronized 进行同步处理, ...

  3. Android开发-API指南-进程与线程

    Processes and Threads 英文原文:http://developer.android.com/guide/components/processes-and-threads.html ...

  4. 一天一个设计模式——(Singleton)单例模式(线程安全性)

    一.模式说明 有时候,我们希望在应用程序中,仅生成某个类的一个实例,这时候需要用到单例模式. 二.模式类图 三.模式中的角色 Singleton角色,该模式中仅有的一个角色,该角色有一个返回唯一实例的 ...

  5. android 开发设计模式---Builder模式

    我们通过一个例子来引出Builder模式.假设有一个Person类,我们通过该Person类来构建一大批人,这个Person类里有很多属性,最常见的比如name,age,weight,height等等 ...

  6. android 开发设计模式---Strategy模式

    假设我们要出去旅游,而去旅游出行的方式有很多,有步行,有坐火车,有坐飞机等等.而如果不使用任何模式,我们的代码可能就是这样子的. 12345678910111213141516171819202122 ...

  7. android 开发设计模式---观察者模式

    情景1 有一种短信服务,比如天气预报服务,一旦你订阅该服务,你只需按月付费,付完费后,每天一旦有天气信息更新,它就会及时向你发送最新的天气信息. 情景2 杂志的订阅,你只需向邮局订阅杂志,缴纳一定的费 ...

  8. Android 开发中三种多线程

    在开发工程中线程可以帮助我们提高运行速度,Android开发中我知道的线程有四个一个是老生长谈的Thread,第二个是asyncTask,第三个:TimetTask,第四个是Looper,四个多线程各 ...

  9. Android开发中常见的设计模式

    对于开发人员来说,设计模式有时候就是一道坎,但是设计模式又非常有用,过了这道坎,它可以让你水平提高一个档次.而在android开发中,必要的了解一些设计模式又是非常有必要的.对于想系统的学习设计模式的 ...

随机推荐

  1. 超文本标记语言(HTML)

    超文本标记语言(HyperText MarkUp Language,HTML) HTML是用来制作网页的标记语言,HTML不需要编译,直接由浏览器解析: HTML文件是一个文本文件,包含了一些HTML ...

  2. cookie与localstorage和sessionstorage的区别比较

    保存位置: 三者均保存在浏览器端,且同源的. 与服务器的关系: cookie 数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递. sessionStorage ...

  3. linux ubuntu12.04 解压中文zip文件,解压之后乱码

    在windows下压缩后的zip包,在ubuntu下解压后显示为乱码问题 1.zip文件解压之后文件名乱码: 第一步 首先安装7zip和convmv(如果之前没有安装的话) 在命令行执行安装命令如下: ...

  4. HDU 3746:Cyclic Nacklace

    Cyclic Nacklace Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  5. 数字证书私钥sign及验证

    package com.epay.bank.test.encrypt; import java.io.FileInputStream; import java.security.KeyStore; i ...

  6. Solr开发文档

    转载:http://www.cnblogs.com/hoojo/archive/2011/10/21/2220431.html Solr 是一种可供企业使用的.基于 Lucene 的搜索服务器,它支持 ...

  7. Codeforces Round #366 (Div. 2) B

    Description Peter Parker wants to play a game with Dr. Octopus. The game is about cycles. Cycle is a ...

  8. Android中直播视频技术探究之---摄像头Camera视频源数据采集解析

    一.前言 在视频直播中一般都是两种视频数据源,一个是摄像头数据,一个是录制桌面数据,而一般来说美女妹子直播都是来自于摄像头数据,游戏直播都是录制桌面数据的,那么今天就来看看第一个数据源数据采集分析,A ...

  9. webform数据导出

    把数据放到一个泛型集合里,再把泛型集合里面的数据放到一个table中,设置好文件路径,然后进行文件读取,最后供用户下载. 数据导出放在一个按钮中就可以了 using System; using Sys ...

  10. windows下mysql自动定时备份bat

    @echo off : basedataset ip=192.168.12.41set user=rootset password=12456 set databaseName=test set /a ...