zoukankan      html  css  js  c++  java
  • 谈谈部分单例设计模式

    饿汉模式

    public class Singleton1 implements Serializable {
        private static Singleton1 instance = new Singleton1();
        private Singleton1(){
    
        }
        public static Singleton1 getInstance(){
            return instance;
        }
    }
    

    是怎么保证线程安全的?

    线程安全的懒汉模式

    双重检测锁(Double Checked Lock DCL) + volatitle

    • DCL,避免多个线程同时指执行到if(instance == null),判断都为true,会排队创新等待创建新对象
    • volatitle关键字 防止CPU指令重排,instance = new Singleton4()不是原子操作,会涉及三个步骤,CPU执行顺序有可能会乱(给实例分配内存空间;调用对象的构造方法,初始化成员字段;将instance 对象指向分配的内存空间)
    public class Singleton4 {
        private volatile static Singleton4 instance;
        private Singleton4(){}
        public static Singleton4 getInstance(){
            if(instance == null){
                synchronized (Singleton4.class){
                    if(instance == null){
                        instance = new Singleton4();
                    }
                }
            }
            return instance;
        }
    }
    

    在第一次调用Singleton4.getInstance()的时候初始化静态变量
    类并不是在加载完之后就会实例static变量。那到底什么时候才会初始化呢?

    1.当遇到new,getstatic,putstatic或者invokestatic这四条字节码指令的时候,如果该类没有进行
    初始化,则需要先初始化.这四条指令对应的是实例化对象,获取一个静态变量,设置一个静态变量(常量
    放在常量池中,不会触发),或者调用静态方法的时候.
    2.当时候反射包的方法对类进行反射调用的时候
    3.当初始化一个类的时候,发现该类的父类还没有进行初始化,则初始其父类
    4.当jvm启动的时候,当用户指定执行一个主类(就是包含main的那个类),虚拟机会先初始化这个类.

    上述的例子是因为满足第一条,执行static方法的时候编译器会生成invokestatic指令,这时候instance没有初始化,所以会执行Instance的构造方法,然后在return返回。

    静态内部类模式

    public class Instance1 {
        private static class Holder{
            private static Instance1 instance = new Instance1();
        }
        private Instance1(){
            System.out.println("instance1 alloc");
        }
        public static Instance1 getInstance(){
            System.out.println("instance1 called");
          
            return instance;
        }
    }
    

    静态内部类和饿汉模式都采用类装载的机制保证,当初始化实例的时候只有一个线程执行,保证了多线程下的安全。
    JVM会在类初始化的阶段(类装载的阶段)创建一个锁,该锁保证多个线程同步执行类初始化的工作,因此在多线程环境下,类加载的机制依然是安全的。
    饿汉模式 是启动就加载,造成资源浪费
    静态内部类 只有在调用getInstance方法的时候 才会去装载内部类,从而完成实例的初始化,不造成资源的浪费。 为比较推荐的单例实现方式。

    参考

    1. https://blog.csdn.net/y1962475006/article/details/79035250
    2. https://blog.csdn.net/y1962475006/article/details/102642440
    3. 深入理解Javax虚拟机-7.3.5初始化
  • 相关阅读:
    模型评估方法
    欠拟合、过拟合、偏差、方差
    机器学习基本概念
    Hive 的基本概念
    Flume的Channel
    Flume的Sink
    Flume的Source
    Flume 安装和配置
    Flume的基本概念
    BIO & NIO & NIO常见框架
  • 原文地址:https://www.cnblogs.com/zendwang/p/14558913.html
Copyright © 2011-2022 走看看