zoukankan      html  css  js  c++  java
  • 线程安全的单例模式

    静态内部类加载

    //静态内部类加载
    class Singleton {
        private static Singleton singleton;
    
        private Singleton() {
        }
    
        private static class SingletonInner {
            private static final Singleton instance = new Singleton();
        }
    
        public static Singleton getSingleton() {
            return SingletonInner.instance;
        }
    }
    

    静态内部类不会在单例加载时加载,当调用 getSingleton() 方法时才会进行加载,达到类似懒汉式效果,并且也是线程安全的。

    类的静态属性只会在第一次加载类时进行初始化,所以上面的方法JVM 帮助我们保证了线程的安全性,在类进行初始化时,其他线程无法进入。

    JVM在类的初始化阶段(即在class被加载后,且被线程使用之前),会执行类的初始化。在执行类的初始化期间,JVM会去获取一个锁。这个锁可以同步多个线程对同一个类的初始化。

    枚举

    //枚举方法
    enum Singleton {
        INSTANCE;
    
        public void method() {
        }
    }
    
    //调用
    class Text {
        public static void main(String[] args) {
            Singleton.INSTANCE.method();
        }
    }
    // ————————————————
    
    public class User {
        //私有化构造函数
        private User(){ }
        //定义一个静态枚举类
        static enum SingletonEnum{
            //创建一个枚举对象,该对象天生为单例
            INSTANCE;
            private User user;
            //私有化枚举的构造函数
            private SingletonEnum(){
                user=new User();
            }
            public User getInstnce(){
                return user;
            }
        }
        //对外暴露一个获取User对象的静态方法
        public static User getInstance(){
            return SingletonEnum.INSTANCE.getInstnce();
        }
    }
    

    自由串行化;保证只有一个实例;线程安全。(TODO 枚举类保证),而且可以避免反射破坏Effective Java 作者所提倡的方法,近乎完美,在继承场景下不适用。

    懒汉式双重检查终极版

    //懒汉式双重检查终极版(推荐)volatile
    class Singleton {
        private static volatile Singleton singleton;//volatile可以禁止重排序,synchronized不行,因此去掉这句还是可能会因重排序导致线程不安全
    
    
        private Singleton() {
        }
    
    
        public static Singleton getSingleton() {
            if (singleton == null) {
                synchronized (Singleton.class) {
                    if (singleton == null) {
                        singleton = new Singleton();//这是关键
                    }
                }
            }
            return singleton;
        }
    }
    

    此方法给singleton 的声明上加了关键字 volatile ,进而解决了低概率的线程不安全问题,如果去掉是不对的。volatile 起到禁止指令重排的作用,在它赋值完成之前,就不会调用读操作(singleton == null)。

    //instance = new Instance();分解
    
    memory=allocate();        //1:分配对象的内存空间
    ctorInstance(memory);     //2:初始化对象
    instance = memory;        //3:设置instance指向刚分配的内存地址
    

    因为new操作可以被分解为如上三个操作,如果这三个操作重排序为132,其他线程就有可能拿到未经初始化的实例。所以去掉volatile会使得线程不安全。

  • 相关阅读:
    【转载】loadrunner使用system()函数调用Tesseract-OCR识别验证码遇到的问题
    实现LoadRunner多个场景的顺序执行(命令行)
    BAT批处理(一)
    BAT批处理(二)
    BAT批处理(五)
    BAT批处理(六)
    BAT批处理(三)
    BAT批处理(四)
    DOS工具
    python3.0与2.x之间的区别
  • 原文地址:https://www.cnblogs.com/wunsiang/p/12713773.html
Copyright © 2011-2022 走看看