zoukankan      html  css  js  c++  java
  • 并发4-单例模式

    模式并不是只有java才有,它是一种思路。

    为什么要用单例?

    多个线程操作同一个对象就要用到单例。保证对象的唯一性

    如何解决这个问题?

    实例化的过程只实例化一次。多个线程开始到销毁到结束都用到同一个实例对象,提供返回实例对象的方法。

    单例模式需要考虑的事项:线程的安全性、性能、懒加载(lazy:延迟加载)

    单例的分类:

      饿汉式:没有延时加载

      线程安全性:在加载的时候已经被实例化(值类型直接放到工作空间,引用类型是将地址放到工作空间,引用类型的实例是放到主内存中),所以只有这一次,线程是安全的

      性能:因为是静态的属性,虚拟机启动的时候就会实例化,所以用成员变量比较少的时候可以使用饿汉式单例,否则成员变量比较多会占用大量内存空间

    public class HungerSingeton {
        //加载的时候产生的实力对象
        private static HungerSingeton Instance = new HungerSingeton();
    
        private HungerSingeton(){
    
        }
        //返回的实例对象
        public static HungerSingeton getInstance(){
            return Instance;
        }
        //测试
        public static void main(String args[]){
            HungerSingeton hungerSingeton = getInstance();
            System.out.println(hungerSingeton);
            HungerSingeton hungerSingeton1 = getInstance();
            System.out.println(hungerSingeton1);
        }
    
    }  

    测试结果:得到是相同的对象

      多线程测试结果:结果也是一样的

      懒汉式:延时加载

      线程安全性:

      性能:对于内存来说比较好,因为用到才创建,但是由于使用了Synchronized它退化到串行执行

    public class HoonSingleton {
    //私有静态
    private static HoonSingleton instance = null;
    //私有构造
    private HoonSingleton(){

    }
    //返回的实例对象,什么使用
    public synchronized static HoonSingleton getInstance(){
    if(null == instance){
    instance = new HoonSingleton();
    }
    return instance;
    }
      
       //改造后让锁的范围更小,只锁对象,而不锁方法,这样多线程访问这个方法的时候会都用有此方法的访问权,但是获取instance的时候会进行排队使用,但是此时还是不保证原子性
      public  static HoonSingleton getInstance1(){
      if(null == instance){
      synchronized(HoonSingleton.class){
      instance = new HoonSingleton();
      }
      }
      return instance;
      }

    //测试
    public static void main(String args[]){
    for (int i = 0; i < 10; i++) {
    new Thread(()->{
    HoonSingleton hoonSingleton = getInstance();
    System.out.println(hoonSingleton);
    },"getInstance").start();
    }
    }
    }

      

    下图出现的这种情况将不保证原子性,有可能创建两个实例。

    HoonSingleton的getInstance方法分析

    HoonSingleton的getInstance1方法的分析

      DCLSingleton(Double-Check-Locking)式

      安全性:保证了原子性

      性能:与懒汉是一致,但是DCL模式会引起指令重排(happens-befor),空指针异常。

    public class DCL {
        //私有静态
        private volatile static DCL instance = null;
        //私有构造
        private DCL(){
    
        }
        //返回的实例对象,什么使用
        public  static DCL getInstance(){
            if(null == instance){
                synchronized(DCL.class){
                    if(null == instance)
                        instance = new DCL();
                }
            }
            return instance;
        }
        //测试
        public static void main(String args[]){
            for (int i = 0; i < 10; i++) {
                new Thread(()->{
                    DCL dcl = getInstance();
                    System.out.println(dcl);
                },"getInstance").start();
            }
        }
    }
    

      

    Volatile+DCL完美解决happens-befor规则带来的困扰

      Holder模式

      声明类的时候,成员变量中不声明实例变量,而放到内部静态类中

      

    public class HolderDome {
      
      private HolderDome(){
      }
    private static class Hoder{ private static HolderDome instance = new HolderDome(); } //保证了原子性,懒加载,性能好,懒加载,内部类只有调用的时候才会创建 public static HolderDome getInstance(){ return Hoder.instance; } }

      目前应用比较广泛的一种单例模式

      

      枚举模式

      

    public class EnumDomeSingleton {
        //私有构造
        private EnumDomeSingleton(){
    
        }
        //建立单例返回值
        public static EnumDomeSingleton getInstance(){
            return EnumHolder.INSTANCE.instance;
        }
    
        //内部枚举
        private enum EnumHolder{
            //定义EnumHolder枚举类型的常量
            INSTANCE;
    
            //定义需要单例的对象
            private EnumDomeSingleton instance;
    
            //定义枚举构造,在使用的时候才会创建实例
            private EnumHolder(){
                instance = new EnumDomeSingleton();
            }
    
            //创建返回的单例实例化
            private  EnumDomeSingleton getInstance(){
                return instance;
            }
    
        }
    
        //测试
        public static void main(String args[]){
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    EnumDomeSingleton enumDomeSingleton = EnumDomeSingleton.getInstance();
                    System.out.println(enumDomeSingleton);
                }
            }).start();
        }
    
    }
    

     安全、性能好、逼格高、懒汉。

        扩展:内部类特性,懒加载。  

  • 相关阅读:
    Uva 10779 collector's problem
    poj 2728 最优比率树(最小生成树问题)
    LA 3126 二分图匹配 最小路径覆盖
    poj 1149 最大流构图
    Step By Step(Java XML篇)
    Step By Step(Java 输入输出篇)
    Step By Step(Java 集合篇)
    Step By Step(Java 线程篇)
    Step By Step(Java 反射篇)
    Step By Step(Java 国际化篇)
  • 原文地址:https://www.cnblogs.com/gnwzj/p/10567338.html
Copyright © 2011-2022 走看看