设计模式|你真的会写单例模式吗?

前言

我们都知道,单例模式是设计模式里最简单的模式,无论是代码还是模式的理解都是最简单的,但是那么简单的东西,你真的写对了吗?

单例模式

单例模式——确保一个类只有一个实例,并提供全局访问点。

要点:

  • 确保程序中一个类最多只有一个实例。
  • 提供访问这个实例的全局点。

乍一看,确实简单,也很好理解,看看怎么实现的,代码:

/**
 * 单例模式
 * @author herongqin
 */
public class RedisSingleton {

    private static RedisSingleton redisSingleton;


    private RedisSingleton(){

    }

    public static RedisSingleton getInstance(){
        if (redisSingleton == null){
            redisSingleton = new RedisSingleton();
        }
        return redisSingleton;
    }
}

说明:目的为了演示,大家不需要关心Redis的内容。

简单吧,把构造器 private 不让别人进行实例化,然后提供一个对外实例化的静态方法,如果想使用这个实例,那就必须通过 getInstance() 方法进行获取具体的实例,是不是满足了单例模式的2个要点?确实是,但是,有句“古话”说得好:程序员要把任何一个应用都当成多线程应用。

提问:如果有多个线程同时去访问getInstance() ,拿到的能确保是同一个实例吗?

 public static RedisSingleton getInstance(){
    if (redisSingleton == null){
        redisSingleton = new RedisSingleton();
    }
    return redisSingleton;
}

那咋搞?这不是违背了单例的核心原则(最多只有一个实例)了吗?有经验的同学,可能已经意识到了,给这段代码加锁啊[赞]。

给 getInstance 加同步锁

我们在 getInstance() 方法上加 synchronized 关键字实现同步锁,这个时候,每个人进入这个方法前,都需要等待上一个线程结束之后,才能进入这个方法,这个时候就可以保证最多只有一个实例了。代码:

 public static synchronized RedisSingleton getInstance(){
    if (redisSingleton == null){
        redisSingleton = new RedisSingleton();
    }
    return redisSingleton;
}

打完收工~!

后来,项目越来越牛B了,自己写的这个单例越来越多的地方在使用,然后他们就发现自己写的代码怎么越来越慢,经过排查,就是因为自己写的这个单例引起的,因为不管你多少人,你都必须先等待上一个人拿完了他才能继续拿,已经验证影响别人的使用了,咋搞?当然是优化了(谁叫甲方是Babababa,哈哈,开玩笑)。

使用 volatile 做双重检查

在静态变量上用volatile 关键字进行修饰,保证变量可见性(多线程下),禁止jvm对该变量进行指令重排,保证了有序性。

/**
 * 单例模式
 * @author herongqin
 */
public class RedisSingleton {
    private static volatile RedisSingleton redisSingleton;
    private RedisSingleton(){
    }
    public static synchronized RedisSingleton getInstance(){
        // 第1次检测
        if (redisSingleton == null){
            synchronized (RedisSingleton.class){
                // 第2次检查
                if (redisSingleton == null){
                    redisSingleton = new RedisSingleton();
                }
            }
        }
        return redisSingleton;
    }
}

在上面的代码中,synchronized 只会锁其中一个片段,而且因为volatile 只会执行一次,所以确保了最多一个实例的特性。

嗯~~ 是不是有点复杂,有没有简单点的,有的!有个更简单的,因为它天生的线程安全,以及默认的private 的构造器,那就是使用枚举实现单例模式。

使用枚举实现单例模式(推荐)

/**
 * 单例模式
 * @author herongqin
 */
public enum RedisSingleton {

    INSTANCE;

    public void set(String key, Object value){
        // 其他代码
    }
    
    public String getString(String key){
        // 其他代码
        return "";
    }

    public static void main(String[] args) {
        // test
        System.out.println(RedisSingleton.INSTANCE.getString("key"));
    }
}

简单吧,但是得从我们正常使用枚举的思维跳出来。

总结

程序员应该把任何一个程序都当成是多线程。共勉~

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