我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android设计模式之单例模式

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android设计模式之单例模式

  1、单例模式常见情景   设计模式中,简单不过的是单例模式。先看看单例模式   Singleton模式可以是很简单的,它的全部只需要一个类可以完成(看看这章可怜的UML图)。但是如果在“对象创建的次数以及何时被创建”这两点上较真起来,Singleton模式可以相当的复杂,比头五种模式加起来还复杂,譬如涉及到DCL双锁检测(double checked locking)的讨论、涉及到多个类加载器(ClassLoader)协同时、涉及到跨JVM(集群、远程EJB等)时、涉及到单例对象被销毁后重建等。   目的:   希望对象只创建一个实例,并且提供一个全局的访问点。

图6.1 单例模式的UML图

  结构是简单的,但是却存在一下情况;   1.每次从getInstance()都能返回一个且的一个对象。   2.资源共享情况下,getInstance()必须适应多线程并发访问。   3.提高访问性能。   4.懒加载(Lazy Load),在需要的时候才被构造。   首先实现1中的单例模式A:   4.public class SingletonA {      5.       6.          9.    private static SingletonA instance = null;      10.       11.    public static SingletonA getInstance() {      12.        if (instance == null) {                              //line 12      13.            instance = new SingletonA();          //line 13      14.        }      15.        return instance;      16.    }      17.}      这个写法我们把四点需求从上往下检测,发现第2点的时候出了问题,假设这样的场景:两个线程并发调用Singleton.getInstance(),假设线程一先判断完instance是否为null,既代码中的line 12进入到line 13的位置。刚刚判断完毕后,JVM将CPU资源切换给线程二,由于线程一还没执行line 13,所以instance仍然是空的,因此线程二执行了new Signleton()操作。片刻之后,线程一被重新唤醒,它执行的仍然是new Signleton()操作。所以这种设计的单例模式不能满足第2点需求。   下面我们继续   实现2中单例模式B:   4.public class SingletonB {      5.       6.          9.    private static SingletonB instance = null;      10.       11.    public synchronized static SingletonB getInstance() {      12.        if (instance == null) {      13.            instance = new SingletonB();      14.        }      15.        return instance;      16.    }      17.}      比起单例A仅仅在方法中多了一个synchronized修饰符,现在可以保证不会出线程问题了。但是这里有个很大(至少耗时比例上很大)的性能问题。除了第一次调用时是执行了SingletonKerriganB的构造函数之外,以后的每一次调用都是直接返回instance对象。返回对象这个操作耗时是很小的,绝大部分的耗时都用在synchronized修饰符的同步准备上,因此从性能上说很不划算。   实现3单例模式C:   4.public class SingletonC {      5.       6.          9.    private static SingletonKerriganD instance = null;      10.       11.    public static SingletonC getInstance() {      12.        if (instance == null) {      13.            synchronized (SingletonC.class) {      14.                if (instance == null) {      15.                    instance = new SingletonC();      16.                }      17.            }      18.        }      19.        return instance;      20.    }      21.}      看起来这样已经达到了我们的要求,除了第一次创建对象之外,其他的访问在第一个if中返回了,因此不会走到同步块中。已经完美了吗?   我们来看看这个场景:假设线程一执行到instance = new SingletonKerriganD()这句,这里看起来是一句话,但实际上它并不是一个原子操作(原子操作的意思是这条语句要么被执行完,要么没有被执行过,不能出现执行了一半这种情形)。事实上高级语言里面非原子操作有很多,我们只要看看这句话被编译后在JVM执行的对应汇编代码发现,这句话被编译成8条汇编指令,大致做了3件事情:   1.给Kerrigan的实例分配内存。   2.初始化Kerrigan的构造器   3.将instance对象指向分配的内存空间(注意到这步instance非null了)。   但是,由于Java编译器允许处理器乱序执行(out-of-order),以及JDK1.5之前JMM(Java Memory Medel)中Cache、寄存器到主内存回写顺序的规定,上面的第二点和第三点的顺序是无法保证的,也是说,执行顺序可能是1-2-3也可能是1-3-2,如果是后者,并且在3执行完毕、2未执行之前,被切换到线程二上,这时候instance因为已经在线程一内执行过了第三点,instance已经是非空了,所以线程二直接拿走instance,然后使用,然后顺理成章地报错,而且这种难以跟踪难以重现的错误估计调试上一星期都未必能找得出来,真是一茶几的杯具啊。   DCL的写法来实现单例是很多技术书、教科书(包括基于JDK1.4以前版本的书籍)上推荐的写法,实际上是不完全正确的。的确在一些语言(譬如C语言)上DCL是可行的,取决于是否能保证2、3步的顺序。在JDK1.5之后,官方已经注意到这种问题,因此调整了JMM、具体化了volatile关键字,因此如果JDK是1.5或之后的版本,只需要将instance的定义改成“private volatile static SingletonKerriganD instance = null;”可以保证每次都去instance都从主内存读取,可以使用DCL的写法来完成单例模式。当然volatile或多或少也会影响到性能,重要的是我们还要考虑JDK1.42以及之前的版本,所以本文中单例模式写法的改进还在继续。   代码倒越来越复杂了,现在先来个返璞归真,根据JLS(Java Language Specification)中的规定,一个类在一个ClassLoader中只会被初始化一次,这点是JVM本身保证的,那把初始化实例的事情扔给JVM好了.   实现4单例模式D:   4.public class SingletonD {      5.       6.          9.    private static SingletonD instance = new SingletonD();      10.       11.    public static SingletonD getInstance() {      12.        return instance;      13.    }      14.}      这种写法不会出现并发问题,但是它是饿汉式的,在ClassLoader加载类后Kerrigan的实例会第一时间被创建,饿汉式的创建方式在一些场景中将无法使用:譬如实例的创建是依赖参数或者配置文件的,在getInstance()之前必须调用某个方法设置参数给它,那样这种单例写法无法使用了。   可带参数单例模式E:   4.public class SingletonE {      5.       6.    private static class SingletonHolder {      7.              10.        static final SingletonE INSTANCE = new SingletonE();      11.    }      12.       13.    public static SingletonE getInstance() {      14.        return SingletonHolder.INSTANCE;      15.    }      16.}      这种写法仍然使用JVM本身机制保证了线程安全问题;由于SingletonHolder是私有的,除了getInstance()之外没有办法访问它,因此它是懒汉式的;同时读取实例的时候不会进行同步,没有性能缺陷;也不依赖JDK版本。   当然,用户以其它方式构造单例的对象,如果设计者不希望这样的情况发生,则需要做规避措施。其它途径创建单例实例的方式有:   1.直接new单例对象   2.通过反射构造单例对象   3.通过序列化构造单例对象。   对于第一种情况,一般我们会加入一个private或者protected的构造函数,这样系统不会自动添加那个public的构造函数了,因此只能调用里面的static方法,无法通过new创建对象。   对于第二种情况,反射时可以使用setAccessible方法来突破private的限制,我们需要做到第一点工作的同时,还需要在在 ReflectPermission("suppressAccessChecks") 权限下使用安全管理器(SecurityManager)的checkPermission方法来限制这种突破。一般来说,不会真的去做这些事情,都是通过应用服务器进行后台配置实现。   对于第三种情况,如果单例对象有必要实现Serializable接口(很少出现),则应当同时实现readResolve()方法来保证反序列化的时候得到原来的对象。   版单例模式F:   4.public class SingletonF implements Serializable {      5.       6.    private static class SingletonHolder {      7.              10.        static final SingletonF INSTANCE = new SingletonF();      11.    }      12.       13.    public static SingletonF getInstance() {      14.        return SingletonHolder.INSTANCE;      15.    }      16.       17.          20.    private SingletonF() {      21.    }      22.       23.          26.    private Object readResolve() {      27.        return getInstance();      28.    }      29.}      2、android中源码单例模式举例   1、日历模块   App路径:packages/providers/CalendarProvider   文件:packages/providers/CalendarProvider/class="lazy" data-src/com/android/provider/calendar/CalendarDatabaseHelper.java   单例代码:   private static CalendarDatabaseHelper sSingleton = null;        public static synchronized CalendarDatabaseHelper getInstance(Context context) {    if (sSingleton == null) {    sSingleton = new CalendarDatabaseHelper(context);    }    return sSingleton;    }    可以看出,这是用到了2中的单例模式B.   2.Collator类   文件:libcore/luni/class="lazy" data-src/main/java/com/ibm/icu4jni/text/Callator.java   libcore/luni/class="lazy" data-src/main/java/com/ibm/icu4jni/text/RuleBasedCallator.java   单例代码:   public static Collator getInstance(Locale locale) {    return new RuleBasedCollator(locale);    }    p;       RuleBasedCollator(Locale locale) {    m_collator_ = NativeCollation.openCollator(locale.toString());    }    static native int openCollator(String locale);    这是上面给出的单例模式E,可带参数的单例模式   3.Editable类   文件:frameworks/base/core/java/android/text/Editable.java   private static Editable.Factory sInstance = new Editable.Factory();        public static Editable.Factory getInstance() {    return sInstance;    }    可见这是单例模式D是实例应用   4.AccessibilityManager类   文件:frameworks/base/core/java/android/view/accessibility/AccessibilityManager.java   public static AccessibilityManager getInstance(Context context) {    synchronized (sInstanceSync) {    if (sInstance == null) {    sInstance = new AccessibilityManager(context);    }    }    return sInstance;    }    这是单例模式C的应用。   android使用单例模式的地方很多,特别是数据库创建时,会使用到单例模式。因每种单例模式试用场景不一样,所以android在不同地方使用了不同的单例模式实现方式。


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android设计模式之单例模式

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android设计模式之单例模式

1、单例模式常见情景设计模式中,简单不过的是单例模式。先看看单例模式Singleton模式可以是很简单的,它的全部只需要一个类可以完成(看看这章可怜的UML图)。但是如果在“对象创建的次数以及何时被创建”这两点上较真
2022-06-06

Android设计模式之单例模式实例

这篇文章主要介绍了Android设计模式之单例模式实例,单例模式是运用最广泛的设计模式之一,在应用这个模式时,单例模式的类必须保证只有一个实例存在
2023-05-16

Android设计模式之单例模式解析

在日常开发过程中时常需要用到设计模式,但是设计模式有23种,如何将这些设计模式了然于胸并且能在实际开发过程中应用得得心应手呢?和我一起跟着《Android源码设计模式解析与实战》一书边学边应用吧!今天我们要讲的是单例模式定义确保某一个类只有
2023-05-30

Android设计模式之单例模式详解

单例模式一个类只有一个实例,并且可以全局访问使用应用场景如账户管理类,数据库操作类等(某个对象频繁被访问使用)常用方式饿汉式懒汉式同步加锁DCL双重加锁验证静态内部类枚举单例饿汉式加载类的同时立即进行初始化操作,对资源消耗很大public
2023-05-30

Android设计模式系列之单例模式

单例模式,可以说是GOF的23种设计模式中最简单的一个。 这个模式相对于其他几个模式比较独立,它只负责控制自己的实例化数量单一(而不是考虑为用户产生什么样的实例),很有意思,是一个感觉上很干净的模式,本人很喜欢这个模式。 android中
2022-06-06

python设计模式之单例模式

单例模式是一种创建型设计模式,它确保一个类有且只有一个特定类型的对象,并提供全局访问点。其意图为:确保类有且只有一个对象被创建为对象提供一个访问点,使程序可以全局访问该对象控制共享资源的并行访问简单理解:单例即为单个实例,也就是每次实例化创
2023-01-30

Android设计模式之单例模式怎么创建

本篇内容介绍了“Android设计模式之单例模式怎么创建”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、概念单例模式是运用最广泛的设计模式
2023-07-06

JavaScript设计模式之单例模式

单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2022-11-13

android开发设计模式之——单例模式详解

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

设计模式 | 单例设计模式

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

java设计模式之单例模式解析

单例模式是最简单但同时也是很重要的一种设计模式,优点有以下几个方面:1.当内存占用特别大的类需要频繁地创建销毁时,单例模式可以节省内存和提高性能,例如myBatis里面的sessionFactory2.当需要对文件做单一读写时,例如同一时间
2023-05-31

Golang 常见设计模式之单例模式

本文主要介绍Go语言中实现单例模式的几种常用套路,经过对比可以得出结论,最推荐的方式是使用 once.Do 来实现,sync.Once 包帮我们隐藏了部分细节,却可以让代码可读性得到很大提升。

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录