设计模式之单例模式,你真的懂了吗???

我是 [闲人球] 这个昵称是由我的梦想(闲云野鹤)+外号(球球)组合而成。我是一个记性成谜的女孩儿,记不住公式记不住代码却能背曲谱,想来还是疼痛的记忆比较深刻。

这博客是对自己学习的一丢丢总结及记录,如果您对 Java、算法、架构感兴趣,可以关注我的动态,我们一起学习。

快乐学习,认真生活;心中有爱,眼里有光

鉴于我记性实在不咋地,备注解释的贼详细,小白一看就懂,话不多说,上代码

/**
 * 饿汉式
 * 类加载到内存后,就实例化一个单例,JVM保证线程安全
 * 唯一缺点:不管用到与否,类加载时就完成实例化
 */
public class Singleton01 {
    private static final Singleton01 INSTANCE = new Singleton01();
    private Singleton01() {
    }
    public static Singleton01 getInstance() {
        return INSTANCE;
    }

    public static void main(String[] args) {
        Singleton01 t1 = Singleton01.getInstance();
        Singleton01 t2 = Singleton01.getInstance();
        System.out.println(t1 == t2);
    }
}
    /**
     * lazy loading
     * 懒汉式
     * 达到了按需初始化的目的,但这种方式在多线程访问的时候是有影响的
     */
    private static Singleton01 INSTANCE;

    private Singleton01() {
    }

    public static Singleton01 getInstance() {
       /*
       分析:
         第一个线程进来后,在还没有new的时候,
         第二个线程来了,判断INSTANCE还是为null,它继续执行new Singleton01(),
         然后第一个线程继续执行,又去new Singleton01(),
         所以INSTANCE 在两个线程中已经不再是一个实例了。
       */
        if (INSTANCE == null) {
//            try {
//                Thread.sleep(1);//增加线程被打断的几率
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            INSTANCE = new Singleton01();
        }
        return INSTANCE;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                System.out.println(Singleton01.getInstance());
            }).start();
        }
    }

在这里插入图片描述

测试结果:全乱了,咋办呢?加锁嘛!

//    可以通过加synchronized来解决,但效率就降低了
    public static synchronized Singleton01 getInstance() {
        if (INSTANCE == null) {
            try {
                Thread.sleep(1);//增加线程被打断的几率
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            INSTANCE = new Singleton01();
        }
        return INSTANCE;
    }

效率降低了,肯定又要想怎么提高效率嘛!传说中的完美写法来啦
人啊最大的特点就是,精(闲)益(的)求(没)精(事)
这里有个坑噢???
DCL(Double Check Lock),一定要加上volatile哦,volatile的两个特点,可见性、有序性
Java的虚拟机内部执行的时候,会对java汇编语言进行优化,会有语句重排

    private static volatile Singleton01 INSTANCE;
    private Singleton01() {
    }
    public static Singleton01 getInstance() {
//        双重检查
        if (INSTANCE == null) {
             synchronized (Singleton01.class) {
                if(INSTANCE==null) {
                    try {
                        Thread.sleep(1);//增加线程被打断的几率
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    INSTANCE = new Singleton01();
                }
            }
        }
        return INSTANCE;
    }
 /**
     * 静态内部类方式
     * 加载外部类时不会加载内部类,这样可以实现懒加载 JVM保证线程安全
     * 虚拟机加载class时只会加载一次,因此只有一个实例
     */
    private Singleton01() {
    }
    private static class SingletonHolder{
        private static  final  Singleton01 INSTANCE = new Singleton01();
    }
    public static  Singleton01 getInstance(){
        return  SingletonHolder.INSTANCE;
    }

最后是java大牛,java创始人之一 Joshua J. Bloch 约书亚·布洛克,他在《Effective Java》这本书中写了一种单例是这样式滴
大牛内心os:你们这些渣渣,一个单例整的这么麻烦,实在是看不下去了…

/**
 * 不仅可以解决线程问题,还可以防止反序列化
 * 为啥可以防反序列化呢?因为枚举没有构造方法
 */
public enum Singleton02 {
    INSTANCE;

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                System.out.println(Singleton02.INSTANCE.hashCode());
            }).start();
        }
    }
}

综上所述,除大牛的堪称perfect外(但俺不会用啊),其它越写越复杂,俺就觉得饿汉挺好的,简单又实用。
工作中啥方式好就用啥,不必追求过多的完美,有时候不完美才是最美的。

果然大半夜的容易写bug啊,取的这名字我都无语了,若发现类名不一样,那可能是漏改了,请见谅…

最后祝各位大佬 心中有爱,眼里有光;快乐学习,认真生活。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值