• JUC并发编程——单例模式(基于狂神说的学习笔记)


    单例模式

    饿汉式:

    package single;
    
    // 饿汉式单例
    public class hungry {
    
        // 饿汉式有可能会浪费内存
        // 因为饿汉式在生成对象时,就创建了所有的空间
        // 单例模式构造器私有
        private hungry(){
    
        }
    
        private final static hungry HUNGRY = new hungry();
        public static hungry getInstance(){
            return HUNGRY;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    普通懒汉式:

    package single;
    
    // 懒汉式单例模式
    public class lazy {
    
        // 单例模式构造器私有
        private lazy(){
            System.out.println(Thread.currentThread().getName()+" gotten");
        }
    
        // 普通懒汉式,在并发下可能会出现问题
        private static lazy lazyMan;
        public static lazy getInstance(){
            if (lazyMan == null){
                lazyMan = new lazy();
            }
            return lazyMan;
        }
    
    
        public static void main(String[] args) {
            for (int i = 0; i < 10; i++) {
                new Thread(()->{
                    lazy.getInstance();
                }).start();
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    使用synchronized与volatile的懒汉式单例

    package single;
    
    // 懒汉式单例模式
    public class lazy {
        
        // 单例模式构造器私有
        private lazy(){
            System.out.println(Thread.currentThread().getName()+" gotten");
        }
    
        // 双重检测锁模式的懒汉式单例
        private volatile static lazy lazyMan;
        private static lazy getInstance(){
            if(lazyMan == null){
                synchronized(lazy.class){
                    if (lazyMan == null){
                        lazyMan = new lazy();// 不是一个原子性操作
                        /**
                         * 1、分配内存空间
                         * 2、执行构造方法,初始化对象
                         * 3、把这个对象指向这个空间
                         * 该过程可能发生指令重排
                         * 因此必须让对象加volatile生成内存屏障
                         */
                    }
                }
            }
            return lazyMan;
        }
    
        public static void main(String[] args) {
            for (int i = 0; i < 10; i++) {
                new Thread(()->{
                    lazy.getInstance();
                }).start();
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    静态内部类

    package single;
    
    // 静态内部类  (不安全)
    public class Holder {
    
        // 单例模式构造器私有
        private Holder(){
    
        }
        public static Holder getInstance(){
            return InnerClass.HOLDER;
        }
        public static class InnerClass{
            private static final Holder HOLDER = new Holder();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    以上单例都不安全,使用反射即可破坏单例

    使用枚举单例模式,反射无法破坏枚举单例

  • 相关阅读:
    IMX6ULL学习笔记(9)——通过SD卡启动Linux内核
    C++11 for循环(基于范围的循环)详解
    加工制造业智慧采购系统解决方案:助力企业实现全流程采购一体化协同
    shell脚本基础
    【计算机视觉 | 语义分割】语义分割常用数据集及其介绍(六)
    CAS解析
    再谈函数的栈帧
    AWK编程语言笔记第一章:基础语法
    windows下快速进入指定目录下的dos窗口
    LabVIEW对EAST长脉冲等离子体运行的陀螺稳态运行控制
  • 原文地址:https://blog.csdn.net/whale_cat/article/details/133932929