真的懂了单例模式了吗?

详细文档地址,更多内容https://www.yuque.com/u21302470/yf53cd/vt151b

一、简介

单例模式主要解决的是,⼀个全局使⽤的类频繁的创建和消费,从⽽提升提升整体的代码的性能。

二、案例场景

  1. 数据库的连接池不会反复创建
  2. spring中⼀个单例模式bean的⽣成和使⽤
  3. 在我们平常的代码中需要设置全局的的⼀些属性保存

三、7种单例模式实现

单例模式的实现⽅式⽐较多,主要在实现上是否⽀持懒汉模式、是否线程安全中运⽤各项技巧。当然也
有⼀些场景不需要考虑懒加载也就是懒汉模式的情况,会直接使⽤ static 静态类或属性和⽅法的⽅式
进⾏处理,供外部调⽤。
1、饿汉式(线程安全)
类加载到内存后,就实例化一个单例,JVM保证线程安全,类在加载的过程中会加锁,保证一次只有一个类在加载

public class Mgr01 {

    private static final  Mgr01 INSTANCE = new Mgr01();

    private Mgr01(){

    }

    public  Mgr01 getInstance(){
        return INSTANCE;
    }
}
public class Mgr02 {

    private static final Mgr02 INSTANCE;

    static {
        INSTANCE = new Mgr02();
    }

    private Mgr02(){
    }

    public Mgr02 getInstance(){
        return INSTANCE;
    }

}

2、CAS(线程安全)

public class Mgr08 {
   private static final AtomicReference<Mgr08> instance = new AtomicReference<Mgr08>();

    private Mgr08 mgr08;

    private Mgr08(){}

    public Mgr08 getInstance(){
        for (;;){
            Mgr08 mgr08 = instance.get();
            if (null != mgr08) {
                return mgr08;
            }
            instance.compareAndSet(null, new Mgr08());
            return instance.get();
        }
    }
}

● java并发库提供了很多原⼦类来⽀持并发访问的数据安全性; AtomicInteger 、 AtomicBoolean 、 AtomicLong 、 AtomicReference 。
● AtomicReference 可以封装引⽤⼀个V实例,⽀持并发访问如上的单例⽅式就是使⽤了这样的⼀个特点。
● 使⽤CAS的好处就是不需要使⽤传统的加锁⽅式保证线程安全,⽽是依赖于CAS的忙等算法,依赖于底层硬件的实现,来保证线程安全。相对于其他锁的实现没有线程的切换和阻塞也就没有了额外的开销,并且可以⽀持较⼤的并发性。
● 当然CAS也有⼀个缺点就是忙等,如果⼀直没有获取到将会处于死循环中。
3、Double Check

public class Mgr06 {
    private static Mgr06 mgr06;

    public Mgr06(){}

    public Mgr06 getInstance(){
        if (null == mgr06) {
            synchronized (Mgr06.class) {
            if (null == mgr06) {
                    mgr06 = new Mgr06();
                }
            }
        }
        return mgr06;
    }
}

● 双重锁的⽅式是⽅法级锁的优化,减少了部分获取实例的耗时。同时这种⽅式也满⾜了懒加载。
4、静态类(线程安全)

public class Mgr03 {
    public  static Map<String, String> map = new ConcurrentHashMap<>();
}

● 以上这种⽅式在我们平常的业务开发中⾮常场常⻅,这样静态类的⽅式可以在第⼀次运⾏的时候直接初始化Map类,同时这⾥我们也不需要到延迟加载在使⽤。
● 在不需要维持任何状态下,仅仅⽤于全局访问,这个使⽤使⽤静态类的⽅式更加⽅便。
● 但如果需要被继承以及需要维持⼀些特定状态的情况下,就适合使⽤单例模式。
5、懒汉式(线程安全的)

public class Mgr05 {
    
    private static Mgr05 mgr05;
    
    private Mgr05(){}
    
    public static synchronized Mgr05 getInstance(){
        if (null != mgr05) {
            return mgr05;
        }
        mgr05 = new Mgr05();
        return mgr05;
    }
}

● 此种模式虽然是安全的,但由于把锁加到⽅法上后,所有的访问都因需要锁占⽤导致资源的浪费。如果不是特殊情况下,不建议此种⽅式实现单例模式。
6、懒汉式(线程不安全的)

public class Mgr04 {

    private static Mgr04 mgr04;

    private Mgr04(){}

    public static Mgr04 getInstance(){
        if (null != mgr04) {
            return mgr04;
        }
        mgr04 = new Mgr04();
        return mgr04;
    }
}

● 单例模式有⼀个特点就是不允许外部直接创建,也就是 new Singleton_01() ,因此这⾥在默认的构造函数上添加了私有属性 private 。
● ⽬前此种⽅式的单例确实满⾜了懒加载,但是如果有多个访问者同时去获取对象实例你可以想象成⼀堆⼈在抢厕所,就会造成多个同样的实例并存,从⽽没有达到单例的要求。
7、Effective Java作者推荐的枚举单例(线程安全)
枚举没有构造方法,不会被反序列化

public enum Mgr09 {
    INSTACE;
    
    public  String test(){
        return "test";
    }
}

Effective Java 作者推荐使⽤枚举的⽅式解决单例模式,此种⽅式可能是平时最少⽤到的。
这种⽅式解决了最主要的;线程安全、⾃由串⾏化、单⼀实例。

@Test
public void test() {
Mgr09.INSTANCE.test();
}

这种写法在功能上与共有域⽅法相近,但是它更简洁,⽆偿地提供了串⾏化机制,绝对防⽌对此实例
化,即使是在⾯对复杂的串⾏化或者反射攻击的时候。虽然这中⽅法还没有⼴泛采⽤,但是单元素的枚
举类型已经成为实现Singleton的最佳⽅法。
但也要知道此种⽅式在存在继承场景下是不可⽤的。
8、内部类(线程安全)

public class Mgr07 {

    private static class Mgr07Holder{
       private static Mgr07 instance = new Mgr07();
    }

    private Mgr07(){}

    public Mgr07 getInstance(){
        return Mgr07Holder.instance;
    }
}

● 静态内部类的方式既保证了类的懒加载,又不会因为加锁耗能
● 这种方式基于JVM虚拟机可以保证多线程并发访问的正确性,就是保证构造方法在多线程下正确的加载

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

推荐阅读更多精彩内容