羊皮书APP(Android版)开发系列(二十二)10分钟秒懂单例模式

单例模式在实际开发过程中经常会用到,我们有必要充分的理解单例模式。单例模式有多种写法,分为懒汉式、饿汉式、双重锁等。

单例模式的定义:

  • 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

单例模式的好处:

  1. 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销;
  2. 由于 new 操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停顿时间。

饿汉式:

public class Singleton1 {
    //私有的默认构造子
    private Singleton() {}
    //已经自行实例化 
    private static final Singleton single = new Singleton();
    //静态工厂方法 
    public static Singleton getInstance() {
        return single;
    }
}
  • 当这个类被加载的时候,new Singleton() 这句话就会被执行,就算是getInstance()没有被调用,类也被初始化了。但是,我们希望他能在我第一次getInstance()时才被真正的创建。这样,我们可以控制真正的类创建的时刻,而不是把类的创建委托给了类装载器。

懒汉式(一):

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
  
    public static Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}
  • 仅能用于单线程中,在多线程中不能正常工作。

懒汉式(二):

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
} 
  • 可在多线程中很好的工作。

静态内部类:

public class Singleton {  
    private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE; 
    }  
}
  • 这种方式在《Effective Java》上推荐使用。这种写法仍然使用JVM本身机制保证了线程安全问题;由于 SingletonHolder 是私有的,除了 getInstance() 之外没有办法访问它,因此它是懒汉式的;同时读取实例的时候不会进行同步,没有性能缺陷;也不依赖 JDK 版本。

双重校验锁:

public class Singleton {
    private volatile static Singleton singleton;

    private Singleton() {
    }

    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
} 
  • volatile 禁止指令重排序优化。也就是说,在 volatile 变量的赋值操作后面会有一个内存屏障(生成的汇编代码上),读操作不会被重排序到内存屏障之前。只能用于JDK 1.5及以上,在JDK1.5以前不能使用。

总结:

  1. 《懒汉式(二)》很常见,但是一般会偏向使用《静态内部类》的方式。
  2. 《双重校验锁》方式也很好,但是它会受到JDK的约束,如果在JDK 1.5及以上使用完全没有问题。
  3. 在Android开发中,在开源框架Android-Universal-Image-Loader的ImageLoader中就是使用《双重校验锁》的方式,所以在Android开发中,我们可以直接使用《双重校验锁》的方式。
  4. Android开发中,单例模式常会用于我们的对业务的封装类中,如:对网络请求的封装、图片加载的封装等。

单例模式使用的一个实际例子见下一篇

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏mySoul

Node 连接mysql数据库

github地址 https://github.com/jxcore/jxcore

33140
来自专栏数据和云

【动手实践】Oracle 12.2 新特性:自动的列表分区创建

2017年来了,我们要启动新的学习征程了。在过去我们一直思考,什么样的内容能够更帮助大家了解和学习到有用的知识? 这个『动手实践』栏目就是这样一个改进和尝试吧,...

30260
来自专栏MySQL实战分享

MongoDB第四期:SQL 与 MongoDB 映射(入门)

传统的关系数据库一般由数据库、表、记录三个层次概念组成,MongoDB是由数据库、集合、文档对象三个层次组成。MongoDB对于关系型数据库里的表,但是集合中没...

39920
来自专栏吴生的专栏

MySQL 慢查询日志

MySQL有一种日志,叫做慢查询日志,主要就是用来记录一些耗时的查询操 作。通过这个日志我们就可以分析出哪些的操作是影响性能的,我们需要对其 进行一些优化措施。

40110
来自专栏Albert陈凯

Hadoop数据分析平台实战——130Hive Shell命令介绍 02(熟悉Hive略过)离线数据分析平台实战——130Hive Shell命令介绍 02(熟悉Hive略过)

离线数据分析平台实战——130Hive Shell命令介绍 02(熟悉Hive略过) 导入数据 Hive的导入数据基本上可以分为三类, 第一种是从linux系...

27950
来自专栏web编程技术分享

第四节 -自己 DIY 一个数据库管理工具1.编写php服务器代码

41540
来自专栏我的博客

PHP Mysql函数汇总表

mysql_affected_rows — 取得前一次 MySQL 操作所影响的记录行数mysql_change_user —  改变活动连接中登录的用户mys...

39650
来自专栏大眼瞪小眼

面试-MySQL总结

2NF:每一个非主属性完全依赖于候选码(属性组的值能唯一的标识一个元组,但是其子集不可以)。

11330
来自专栏IT技术精选文摘

Mysql锁机制分析

1.1K40
来自专栏淡定的博客

sql注入入门学习(数字型)(连载中)

在MySQL中,表名存放在information_schema数据库下tables表table_name字段中、查表名我们主要用到的是TABLES表

35740

扫码关注云+社区

领取腾讯云代金券