• 线程安全的单例模式


    单例模式是一种常用的设计模式,其定义是单例对象的类只能允许一个实例存在。下面来看看几种常见的单例模式的写法,以及如何保证线程安全的实现。

    1、饿汉式(线程安全)

      这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。但是在类装载的时候就完成实例化,没有达到懒加载的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。

    public class Singleton {
    
        private static final Singleton instance = new Singleton();
    
        private Singleton(){}
    
        public static Singleton getInstance(){
            return instance ;
        }
    }
    

    2、懒汉式(线程安全)

      这种方式效率太低了,每个线程在想获得类的实例的时候,执行getInstance()方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了。也就是我们之前提到的同步的粒度太粗,synchronized 同步代码应该是越细越好。

    public class Singleton {
    
        private static Singleton singleton;
    
        private Singleton() {}
    
        public static synchronized Singleton getInstance() {
            if (singleton == null) {
                singleton = new Singleton();
            }
            return singleton;
        }
    }
    

    3、懒汉式(线程安全)的细粒度优化(双重锁机制)

      对上一种模式进行优化,这里判断了两次是否为 null 是因为在并发环境中当线程一执行了第一个判断的时候是为null,可此刻另外一个线程正好执行完初始化操作,在释放锁以后该线程并不知道已经初始化,如果此刻进入代码块不进行再次判断会再初始化一次,这就违背了单例模式的初衷了。

    public class Singleton {  
    
         private static Singleton instance;
      
         private Singleton (){}   
    
         public static Singleton getInstance(){ 
    
           if (instance == null){
               synchronized(Singleton.class){
                   if (instance == null)
                       instance = new Singleton(); 
               }
           }
           return instance;
         }
     }
    

    4、静态内部类(懒加载,线程安全)

      这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有懒加载的作用,而静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。避免了线程不安全,延迟加载,效率高。

    public class Singleton {
    
        private Singleton() {}
        //内部类在外部类调用的时候才会被初始化
        // 内部类一定要在方法调用之前初始化
        private static class SingletonInstance {
            private static final Singleton instance = new Singleton();
        }
        // static 使单例空间共享
        // final使得方法不能被重写重载
        public static final Singleton getInstance() {
            return SingletonInstance.instance;
        }
    }
    

      这里可以在私有的构造方法中进行一个双重锁的判断,定义一个 flag来判断该构造是否被重复调用,来防止反射的侵入。

      除此之外还可以使用枚举类的方式来实现单例模式。由于实际工作中并未发现有人这么做,这里就不演示了。

  • 相关阅读:
    agc015D A or...or B Problem
    agc016E Poor Turkeys
    CTSC2016时空旅行
    假期的宿舍[ZJOI2009]
    上白泽慧音(luogu P1726
    小K的农场(luogu P1993
    Cashier Employment(poj1275
    Intervals(poj1201
    序列分割[Apio2014]
    特别行动队[APIO2010]
  • 原文地址:https://www.cnblogs.com/wuzhenzhao/p/9923309.html
Copyright © 2020-2023  润新知