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();
        }
    
    }
    

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

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

  • 相关阅读:
    Winform WebBrowser引用IE版本问题
    MarkdownPad怎么显示表格
    C# winForm里窗体嵌套
    code first 创建数据库
    mvc+webapi+dapper+ef codefirst项目搭建
    MongoDB:逐渐变得无关紧要
    fiddler打开后 浏览器就上不了网的解决方法
    Android学习系列(16)--App列表之圆角ListView
    Android应用程序结构总结
    android程序监听home键与电源键
  • 原文地址:https://www.cnblogs.com/gnwzj/p/10567338.html
Copyright © 2011-2022 走看看