2--∞:单例模式(Singleton Pattern)

前言

此篇文章只是本人学习 单列模式(Singleton Pattern) 使用的笔记,如有雷同,纯属缘分!

什么是单例?

单例模式(Singleton Pattern):确保某一个类只有一个实例,并提供该实例的全局访问,其构造函数私有化。它是 Java 中最简单的设计模式(Design Pattern)。

设计模式(Design Pattern):前人对特定问题经过无数次的经验总结之后 ,提出的能够解决它的优雅的方案。它不是一种技术与方法,而是一种思想!

本质:

控制实例数量

三大要点:

线程安全
延迟加载
序列化与反序列化安全

单例的几种写法

1.饿汉式
public class Singleton {
    //上去就是干,直接实例化
    private static Singleton instances = new Singleton();
    //私有化构造函数,阻止实例化对象
    private Singleton() {}
    //直接返回已经实例化了的对象
    public static Singleton getInstances() {
        return instances;
    }
    public void doSomething() {
        //doSomething....
    }
}

饿汉式 这种实现单例方法是最简单粗暴的,它在类开始加载时就初始化了(但浪费内存),而且在多线程中是安全的,是典型的空间换时间。如果单例对象初始化非常快,而且占用内存非常小的时候,用这种方式是比较合适的,可以直接在应用启动时加载并初始化。

2.懒汉式,线程不安全
public class Singleton {
    private static Singleton instances = null;
    private Singleton() {}
    //如果发现没有实例对象,就构造一个;如果有实例对象,直接返回
    public static Singleton getInstances() {
        if (instances == null) {
            instances = new Singleton();
        }
        return instances;
    }
    public void doSomething() {
        //doSomething
    }
}

懒汉式 就是将单例的初始化操作,延迟加载 到需要的时候才进行,这样做在某些场合中有很大用处。比如某个单例用的次数不是很多,但是这个单例提供的功能又非常复杂,而且加载和初始化要消耗大量的资源,这个时候使用懒汉式就是非常不错的选择。但它在 多线程中不安全(比如,有两个线程,一个是线程 A,一个是线程 B,它们同时调用 getInstances 方法,就可能导致并发问题),是典型的时间换空间

3.懒汉式,线程安全
public class Singleton {
    private static Singleton instances = null;
    private Singleton() {}
    public static Singleton getInstances() {
        //加入同步锁 synchronized
        synchronized (Singleton.class) {
            if (instances == null) {
                instances = new Singleton();
            }
            return instances;
        }
    }
    public void doSomething() {
        //doSomething
    }
}

这种是最常见的解决同步问题的一种方式,使用同步锁 **synchronized (Singleton.class) **防止多线程同时进入造成 getInstances 被多次实例化。

4.懒汉式,双重校验锁
public class Singleton {
    // 对保存实例的变量添加 volitile 的修饰
    private volatile static Singleton instances = null;
    private Singleton(){}
    public static Singleton getInstances(){
        //先检查实例是否存在,如果不存在才进入下面的同步块
        if(instances == null){
            //同步块,线程安全的创建实例
            synchronized (Singleton.class) {
                //再次检查实例是否存在,如果不存在才真正的创建实例
                if (instances == null){
                    instances = new Singleton();
                }
            }
        }
        return instances;
    }
    public void doSomething() {
        //doSomething
    }
}

双重校验锁 指的是:并不是每次进入 getInstances 方法都需要同步,而是先不同步,进入方法过后,先检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查。进入同步块后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例。这是第二重检查。

双重加锁机制的实现会使用一个关键字 volatile ,它的意思是:被 volatile 修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。

5.静态内部类
public class Singleton {
    //类级的内部类,也就是静态类的成员式内部类,该内部类的实例与外部类的实例
    //没有绑定关系,而且只有被调用时才会装载,从而实现了延迟加载
    private static class SingletonHolder {
        //静态初始化器,由JVM来保证线程安全
        private static Singleton instances = new Singleton();
    }
    private Singleton() {}
    public static Singleton getInstances() {
        return SingletonHolder.instances;
    }
    public void doSomething() {
        //doSomething
    }
}

这样实现出来的单例类就是线程安全的,而且使用起来非常简洁。

6.枚举类型单例模式
public enum Singleton{
    //定义一个枚举的元素,它就是Singleton的一个实例
    instance;
    public void doSomething(){
        // do something ...
    }    
}

这种方法是根据 Effective Java 书中的说法,默认枚举实例的创建是 线程安全 的.(创建枚举类的单例在 JVM 层面也是能保证线程安全的), 所以不需要担心线程安全的问题,所以理论上枚举类来实现单例模式是最简单的方式。

总结

以上就是 单例模式 的几种写法。分别是饿汉懒汉同步锁双重校验锁静态内部类枚举。我们可以根据不同的场景选择最喜欢的一种单例模式吧!

如何使用

当需要控制一个类的实例只能有一个,而且客户只能从一个全局访问点访问它时,可以选用单例模式,这些功能恰好是单例模式要解决的问题

番外阅读

单例模式的一些注意点

参考

ANDROID设计模式之单例模式
设计模式干货系列:(四)单例模式【学习难度:★☆☆☆☆,使用频率:★★★★☆】

                                        -- 默默的划水ing--
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容