栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

学记-设计模式-单例模式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

学记-设计模式-单例模式

学记-设计模式-单例模式 前言

​ 最近在准备面试,梳理知识的时候发现自己总是边学边忘,很多知识点容易混淆。经过反思发现,我这个死脑筋就是记不住好。所以我决定把他们都记在笔记里,这样既可以加深我印象,又可以和大家一起学习讨论。

​ 说回单例模式,最近看了小傅哥和遇见狂神说的设计模式,有很多有趣的地方。本文是对单例模式的学习笔记。

介绍

​ 单例模式,属于创建型模式,也就是要保证一个类仅有一个实例,并提供一个访问它的全局访问点。

实现

​ 单例模式的实现方式比较多,我这边列举7种方式。

1、饿汉式(线程安全)
public class Hungry_0 {

    private static Hungry_0 instance = new Hungry_0();

    public Hungry_0() {
    }

    public static Hungry_0 getInstance() {
        return instance;
    }

}

在程序启动的时候直接运行加载,后续有外部需要使用的时候获取即可。

但是这种方式有个不好的地方就是会提前加载资源到内存中,就好比,你打开的是应用的个人中心,应用却把非个人中心的资源也加载了。

2、懒汉式(线程不安全)
private static Lazy_0 INSTANCE;
    private Lazy_0() {}
    private static Lazy_0 getInstance() {
        if (null == INSTANCE) {
            INSTANCE = new Lazy_0();
        }
        return INSTANCE;
    }

在多线程情况下不安全,并发问题。 3、懒汉式-方法级锁(线程安全)

private static Lazy_1 INSTANCE;

    private Lazy_1() {
    }
    private synchronized static Lazy_1 getInstance() {
        if (null == INSTANCE) {
            INSTANCE = new Lazy_1();
        }
        return INSTANCE;
    }

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

	//volatile 防止指令重排    
	private volatile static Lazy_2 INSTANCE;

    private Lazy_2() {
    }
    private static Lazy_2 getInstance() {
        if (null == INSTANCE) {
            synchronized (Lazy_2.class){
                if (null == INSTANCE) {
                    INSTANCE = new Lazy_2();
                }
            }
        }
        return INSTANCE;
    }

双重锁的方式是方法级锁的优化,减少了部分获取实例的耗时。

但是在特定情况下不安全,不过比较少见,可以用来炫技,比如反射。

   //尝试使用反射创建一个新的实例
   Lazy_2 instance = Lazy_2.getInstance();
   Constructor constructor = 	 	  (Constructor)instance.getClass().getDeclaredConstructor(null);
   constructor.setAccessible(true);
   Lazy_2 clone = constructor.newInstance();
   System.out.println(instance); //lazy.Lazy_2@39a054a5
   System.out.println(clone); //lazy.Lazy_2@71bc1ae4

怎样防止上面的反射创建呢,我们可以在构造方法中加入反射校验

    //volatile 防止指令重排
    private volatile static Lazy_3 INSTANCE;

    private Lazy_3() {
        if (null != INSTANCE) {
            throw new RuntimeException("Cannot reflectively create use invoke");
        }
    }
    private static Lazy_3 getInstance() {
        if (null == INSTANCE) {
            synchronized (Lazy_3.class) {
                if (null == INSTANCE) {
                    INSTANCE = new Lazy_3();
                }
            }
        }
        return INSTANCE;
    }

当然,还有别的方法可以再次创建实例。(道高一尺,魔高一丈)

5、懒汉式-枚举(线程安全)
public enum Lazy_4 {
    
    INSTANCE;

    private static Lazy_4 getInstance() {
        return INSTANCE;
    }
}

为什么枚举类是线程安全的呢,通过源码查看发现枚举类也是私有构造器。

尝试使用反射去new一个新的实例

        Lazy_4 instance = Lazy_4.getInstance();
        System.out.println(instance.hashCode());//lazy.Lazy_4@39a054a5
        //尝试使用多次方式创建对象
        Constructor constructor = Lazy_4.class.getDeclaredConstructor(null);
		constructor.setAccessible(true);
        System.out.println(constructor.newInstance());

却提示找不到该构造方法,找不到构造方法??

为什么找不到呢,经过一系列查找,最终通过字节码查看下发现,并没有无参构造方法。

再试试反射,之后出现了“Cannot reflectively create enum objects”,原来是在newInstance的时候会判断该类是否是枚举类,防止其多次创建实例。

6、懒汉式- CAS(线程安全)
private static final AtomicReference INSTANCE = new AtomicReference();

    private static boolean flag = true;
    private Lazy_5() {
    }
    private static final Lazy_5 getInstance() {
        for (; ; ) {
            Lazy_5 instance = INSTANCE.get();
            if (null != instance) return instance;
            INSTANCE.compareAndSet(null, new Lazy_5());
            return INSTANCE.get();
        }
    }

比较替换的方法,当然CAS也有一个缺点就是忙等,如果一直没有获取到将会处于死循环中。 7、懒汉式- 静态内部类(线程安全)

    private static class SingletonHolder {
        private static Lazy_6 instance = new Lazy_6();
    }
    private Lazy_6() {
    }
    public static Lazy_6 getInstance() {
        return SingletonHolder.instance;
    }
总结

这也是我第一次把学习笔记记在这里,如果有哪里写得不对的地方,也请大家指出。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/750230.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号