设计模式小抄(一) -- 单例模式

本文深入探讨单例模式的五种实现方法:饿汉式、懒汉式、双重检测锁、静态内部类及枚举单例,剖析每种方法的特点与适用场景,助你掌握单例模式的核心原理。

设计模式作为开发(面试)必备(必考)知识, 我们还是要好好掌握. 掌握不好,那是因为你没有准备好小抄~

啥是小抄, 就是参考别人的答案,加上自己手抄.

小抄参考资源:

《JAVA与模式》之单例模式

设计模式(二)单例模式的七种写法

单例模式

先抄个 UML

单例模式的数据结构很简单,就是一个单一的示例对象

单例模式的特点

  • 单一实例
  • 由自己内部创建
  • 提供所有对象唯一访问实例

1、饿汉式单例

很奇怪的命名方式, 咱也不知道为啥这样叫,咱也不敢问,先抄吧~

public class SimpleSingleton {
    //静态对象,在对象初始化时,进行创建
    private static SimpleSingleton instance = new SimpleSingleton();

    private SimpleSingleton() {
    }

    //返回已经创建好的实例对象
    public static SimpleSingleton getInstance() {
        return instance;
    }
}
复制代码

饿汉式 其实是一种比较形象的称谓。既然饿,那么在创建对象实例的时候就比较着急,饿了嘛,于是在装载类的时候就创建对象实例。(抄的)

在类加载过程中, 当我们在初始化对象时, 会将对象中的静态属性初始化,因此这里主要时利用了 类加载的相关特性,从而达到了单例的效果.

特点
  • 空间换时间 -- 程序启动即存在(容易浪费内存),节省使用时创建时间(感觉节省不了多少)--弊端较大
  • 线程安全 -- 利用类加载进行初始化(只会初始化一次静态对象),线程安全

2、懒汉式单例

咱也不知道该怎么调侃这个命名,先抄就对了~

public class LazySingleton {
    //先不初始化了, 节省点空间
    private static LazySingleton instance;

    
    private LazySingleton() { }

    //加了个锁,排队访问吧 弟弟
    public static synchronized LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}
复制代码

参考资料(答案)里面有个非线程安全的懒汉模式,那个就是个弟弟,送命题,不抄

懒汉式 其实是一种比较形象的称谓。既然懒,那么在创建对象实例的时候就不着急。会一直等到马上要使用对象实例的时候才会创建,懒人嘛,总是推脱不开的时候才会真正去执行工作,因此在装载对象的时候不创建对象实例。(也是抄的)

特点
  • 时间换空间 - 只有在使用时,才会初始化.避免浪费空间资源
  • 低并发 - synchronized 将疯狂请求的弟弟一个个安排在门口,响应缓慢

3、双重检测锁单例(DoubleCheckLock)

也不知道这个英语有没有拼错,没得抄只能蒙一下了,万一对了呢~

public class DCLSingleton {
    //volatile 内存可见,就是可以实时查看到更新
    private volatile static DCLSingleton instance = new DCLSingleton();

    private DCLSingleton() {
    }

    
    public static DCLSingleton getInstance() {
        if (instance == null) {
            //妹妹进来了,安排好,就那么一次机会 好好珍惜
            synchronized (DCLSingleton.class) {
                //如果进来了个弟弟,撵出去
                if (instance == null) {
                    //初始化好
                    instance = new DCLSingleton();
                }
            }
        }
        return instance;
    }
}
复制代码

双重检查加锁机制指的是:并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法后,先检查实例是否存在,如果不存在才进行下面的同步块,这是第一重检查,进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。(还是抄的)

这个模式,主要依赖于 volatile 关键字.

volatile 关键字的作用是: 它所修饰的变量,在发生变化时,会直接写入内存,与其他线程共享,从而确保在多线程下能正确获取该变量的值

特点
  • 资源利用率高 - 解决了 懒汉模式 中对方法加锁的尴尬情况
  • 有缺陷 - 高并发环境下也有一定的缺陷,虽然发生的概率很小

4、 静态内部类单例模式(Lazy initialization holder class)

这次名字英语抄对了~逼格上来了~

public class LIHCSingleton {
    private LIHCSingleton() {
    }

    //内部类,类加载过程中,不会初始化
    private static class SingletonHolder {
        private static LIHCSingleton instance = new LIHCSingleton();
    }


    public LIHCSingleton getInstance() {
        //调用内部类时,进行初始化
        return SingletonHolder.instance;
    }
}
复制代码

静态内部类单例模式 - 与饿汉模式类似,通过JVM类加载机制实现了线程安全的单例模式,并且通过静态内部类延迟加载机制,解决了 饿汉模式中出现的弊端.(自己写的)

特点
  • 饿汉模式的优点都有
  • 线程安全
  • 资源利用率高
  • 就很棒~
相关知识

什么是类级内部类?

  • 简单点说,类级内部类指的是,有static修饰的成员式内部类。如果没有static修饰的成员式内部类被称为对象级内部类。

  • 类级内部类相当于其外部类的static成分,它的对象与外部类对象间不存在依赖关系,因此可直接创建。而对象级内部类的实例,是绑定在外部对象实例中的。

  • 类级内部类中,可以定义静态的方法。在静态方法中只能够引用外部类中的静态成员方法或者成员变量。

  • 类级内部类相当于其外部类的成员,只有在第一次被使用的时候才被会装载。

5、枚举单例

终于快抄完了,酥服

public enum EnumSingleton {
    singleton;


    public void excute(){
        //todo 做点啥都行, 你说了算
    }

}
复制代码

默认枚举实例的创建是线程安全的,并且在任何情况下都是单例.(强,无敌)

《Effective Java》中有写到: 单元素的枚举类型已经成为实现Singleton的最佳方法.

使用枚举来实现单实例控制会更加简洁,而且无偿地提供了序列化机制,并由JVM从根本上提供保障,绝对防止多次实例化,是更简洁、高效、安全的实现单例的方式。

总结

三分靠打拼,七分天注定,剩下的90分, 你们加油哦~骚年

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值