设计模式-单例模式

介绍

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。即一个类只有一个对象实例。

实际运用

例如一个嵌入到微信的项目,里面有这微信登入、微信分享文章、微信获取位置等功能。那么用到微信登入这个功能,首先就要获取access_token。下面是关于获取access_token的说明。

access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。

公众平台的API调用所需的access_token的使用及生成方式说明:
1、建议公众号开发者使用中控服务器统一获取和刷新Access_token,其他业务逻辑服务器所使用的access_token均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致access_token覆盖而影响业务;
2、目前Access_token的有效期通过返回的expire_in来传达,目前是7200秒之内的值。中控服务器需要根据这个有效时间提前去刷新新access_token。在刷新过程中,中控服务器对外输出的依然是老access_token,此时公众平台后台会保证在刷新短时间内,新老access_token都可用,这保证了第三方业务的平滑过渡;
3、Access_token的有效时间可能会在未来有调整,所以中控服务器不仅需要内部定时主动刷新,还需要提供被动刷新access_token的接口,这样便于业务服务器在API调用获知access_token已超时的情况下,可以触发access_token的刷新流程。

当然,我这里只是介绍如何用单例模式保存这些信息,微信js的access_token也是如此。文中的map就是用来存储access_token和access_token创建时间。

分类

单例模式的创建方式可以分为两种,一种是饿汉式、一种是懒汉式。顾名思义饿汉式就是迫切的把实例初始化,懒汉式就是当调用时在进行初始化。

饿汉式

由于饿汉式篇幅较少,所以先介绍

public class EagerlySingleton {
    
    private EagerlySingleton(){};
    
    private static Map<String,Object> map = new HashMap<String, Object>();
    
    /**
    * <p>Description: 解决多线程问题方式二(饿汉)</p>
    */
    public static synchronized Map<String,Object> getMemoryMap(){
        return map;
    }

}

代码见github地址
这种饿汉式的单例模式,首先解决了多线程的问题。EagerlySingleton 类创建的同时就已经创建好一个静态的对象供系统使用,所以是线程安全的。唯一的缺点就是EagerlySingleton 类太早被创建,而里面的map如果是很久才被使用,内存一直被占用着。

懒汉式

public class FirstSingleton {
    
    private FirstSingleton(){};
    
    private static Map<String,Object> map = null;
    
    public static Map<String,Object> getMemoryMap()
    {
        if (map == null)
            map = new HashMap<String, Object>();

        return map;
    }

}

代码见github地址
private FirstSingleton(){};私有构造器保证该类不被外部类实例化(当然反射可以突破这种限制)。通过调用getMemoryMap方法获得这个类中的map属性。但是这个方法不是线程安全的因为有可能第一个调用这个方法的已经正在创建map,然后第二个调用的进入if判断时map还是为空,然后就被覆盖了(怎么感觉map被覆盖了还是不会出问题的。。。)。

懒汉式-解决多线程问题方式一

public class SecondSingleton {
    
    private SecondSingleton(){};
    
    private static Map<String,Object> map = null;
    
    /**
    * <p>Description: 解决多线程问题方式一</p>
    */
    public static synchronized Map<String,Object> getMemoryMap(){
        if (map == null)
            map = new HashMap<String, Object>();

        return map;
    }

}

代码见github地址
在getMemoryMap方法中加入synchronized 关键字将整个方法加锁,这样做是线程安全了,但是以后的每次调用都会加锁,其实只要在map实例化的时候加锁就行了,然后就出现双重检查(Double-check),如下

懒汉式-解决多线程问题方式三(方式二见饿汉式)

public class DoubleCheckSingleton {
    
    private DoubleCheckSingleton(){};
    
    private volatile static Map<String,Object> map = null;
    
    /**
    * <p>Description: 解决多线程问题方式三(双重检查加锁)</p>
    */
    public static Map<String,Object> getMemoryMap2(){
        if (map == null){
            synchronized(DoubleCheckSingleton.class){
                if (map == null){
                    map = new HashMap<String, Object>();
                }
            }
        }
        return map;
    }

}

代码见github地址
双重检查加锁这种写法解决了线程问题及效率问题,然而还有一种静态内部类的写法。
懒汉式-解决多线程问题方式四


public class StaticInnerClassSingleton {
    
    private StaticInnerClassSingleton(){};
    
    private static class MapHandle{
        private volatile static Map<String,Object> map = new HashMap<String, Object>();
    }
    
    /**
    * <p>Description: 解决多线程问题方式四(静态内部类)</p>
    */
    public static final Map<String,Object> getMemoryMap(){
        return MapHandle.map;
    }

}

代码见github地址
静态内部类完美的解决了性能和线程安全问题。


总结

单例模式的介绍到这里就结束了,上面的map只是单例模式模式的一种运用(或许存在问题。。。),实际开发中还会有各种各样会用到单例模式的例子。
JDK中就有许多,例如Runtime 等等

public class Runtime {
    private static Runtime currentRuntime = new Runtime();

    public static Runtime getRuntime() {
        return currentRuntime;
    }

    private Runtime() {}
}

这里还介绍了一种实现Serializable 的方式

Serialization
If the Singleton class implements the java.io.Serializable interface, when a singleton is serialized and then deserialized more than once, there will be multiple instances of Singleton created. In order to avoid this the readResolve method should be implemented. See Serializable () and readResolve Method () in javadocs.

public class Singleton implements Serializable {
        ...

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

推荐阅读更多精彩内容

  • 单例模式 介绍 为了节约系统资源,有时需要确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,我们无法再...
    666真666阅读 343评论 0 6
  • 概念 java中单例模式是一种常见的设计模式,单例模式的写法有好几种,比较常见的有:懒汉式单例、饿汉式单例。单例模...
    怡红快绿阅读 454评论 0 0
  • 单例模式(Singleton Pattern)是众多设计模式中较为简单的一个,同时它也是面试时经常被提及的问题,如...
    廖少少阅读 560评论 0 1
  • 在Java设计模式中,单例模式相对来说算是比较简单的一种构建模式。适用的场景在于:对于定义的一个类,在整个应用程序...
    时待吾阅读 248评论 0 0
  • 模式介绍 单例模式是应用最广泛的模式之一。 单例模式是为了确保一个类在整个项目中只有一个实例对象。 单例模式最大的...
    黑色小老虎丶阅读 523评论 0 2