• 设计模式 | 单例模式


    1. 最简单的实现方式

    之前面试百度的时候,面试官问我:“单例模式需要注意的点是什么?”,当时感觉答得有点乱,
    经过之后的学习总结下来应该注意以下两点:

    1. 构造方法一定要用private修饰!不可以被new出来!
    2. 并发场景下也要保证它是一个对象!
    public class Singleton {
    
        private static Singleton INSTANCE;
    
        // 构造方法一定要用private修饰!
        private Singleton() {
        }
    
        public static Singleton getSingleton() {
        // 懒加载实现
            if (INSTANCE == null) {
                INSTANCE = new Singleton();
            }
            return INSTANCE;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    存在问题:

    1. 多线程环境下不适用!会出现被new多次的问题!

    2. DCL双重检查实现

    dcl —> duplication check lock

    public class Singleton {
    
        private volatile static Singleton INSTANCE;
    
        // 构造方法一定要用private修饰!
        private Singleton() {
        }
    
        public static Singleton getSingleton() {
            if (INSTANCE == null) {
                synchronized(Singleton.class){
                    if (INSTANCE == null) {
                        INSTANCE = new Singleton();
                    }
                }
            }
            return INSTANCE;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    解释:

    1. 为什么使用volatile?

      防止指令重排,获取到半个对象

    2. 为什么要两次判断?

      防止特殊情况:俩对象同时进入到 if (INSTANCE == null) 这个判断中


    3. 静态内部类实现

    public class Singleton2 {
    
        // 构造方法一定要用private修饰!
        private Singleton2() {
        }
    
        private static class Singleton2Dummy {
            private static final Singleton2 INSTANCE = new Singleton2();
        }
    
        public static Singleton2 getSingleton() {
            return Singleton2Dummy.INSTANCE;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    说明:

    1. 这是线程安全的,为什么?

      静态内部类是静态的,所以是类的一部分,加载当前类(Singleton2 )的时候也会加载这个内部类,并给他的值初始化,相当于已经实例化好了这个内部类,不管你调用与否,它都在这里生成了,且是独一份的!

    缺点:
    2. 非要说缺点那就是他不管用不用都被实例化了,会占用点内存!


    4. 枚举类 (最优解)

    《Effective Java》作者是约书亚·布洛克(Joshua Bloch)在书中提到单例模式最优解如下:

    public enum Singleton3 {
    
        INSTANCE;
    
        public void 具体实现() {
        }
    
        public static void main(String[] args) {
            IntStream.range(1, 100).forEach(num -> {
                new Thread(() -> {
                    System.out.println(Singleton3.INSTANCE.hashCode());
                }).start();
            });
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    说明:

    1. 线程安全:是通过jvm层面的实现来保证线程安全的
    2. 枚举类没有构造方法
  • 相关阅读:
    这些视频转音频软件你知道吗?
    《数据安全法》出台一周年,看哪四大变化来袭?
    Flask 学习-48.Flask-RESTX 使用api.model() 模型工厂
    Skywalking的知识
    9.DesignForManufacture\CreateArtwork...
    使用WSL2技术在Windows子系统中安装Ubuntu并安装docker及docker-compose(图文详细教程)
    腾讯被曝要求员工还清90万房贷再离职;苹果因不附带充电器被判赔偿消费者7000元;Git 2.6发布|极客头条
    大数据平台搭建2024(一)
    Python爬虫——爬虫基础模块和类库(附实践项目)
    生产经验篇(2)——真实环境的MySQL机器配置规划
  • 原文地址:https://blog.csdn.net/weixin_40597409/article/details/126645093