zoukankan      html  css  js  c++  java
  • 单例与多线程

    一。饿汉模式

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

      第一次加载类时就会创建Singleton 实例,所以是线程安全的。另一方面,如果这个Singleton 实例的创建非常消耗系统资源,

    而应用始终都没有使用Singleton 实例,那么创建Singleton 消耗的系统资源就被白白浪费了。

    二。饱汉模式

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

      线程不安全:两个线程A 和B 同时进入该方法的情形
    1. A 进入if 判断,此时foo 为null,因此进入if 语句
    2. B 进入if 判断,此时A 还没有创建foo,因此foo 也为null,因此B 也进入if 语句
    3. A 创建了一个Foo 并返回
    4. B 也创建了一个Foo 并返回

    三。解决方法

    1.同步方法

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

      这种解决办法的确可以防止错误的出现,但是它却很影响性能:每次调用getInstance 方法的时候都必须获得
    Singleton 的锁,而实际上,当单例实例被创建以后,其后的请求没有必要再使用互斥机制了

    2.同步块

      
          
       public static Singleton getInstance(){     
         if(single == null){       
              synchronized (Singleton.class) {    //保证了同一时间只能只能有一个对象访问此同步块          
                  if(single == null){        
                      single = new Singleton();             
                  }       
              }   
         }     
         return single;    
       }   

      上述描述似乎已经解决了我们面临的所有问题,但从JVM 的角度讲,这些代码仍然可能发生错误。对于JVM 而言,它执行的是一个个Java 指令。
    在Java 指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton()语句是分两步执行的。但是JVM 并不保证这两个操作的
    先后顺序,也就是说有可能JVM 会为新的Singleton 实例分配空间,然后直接赋值给instance 成员,然后再去初始化这个Singleton 实例。这样就
    可能出错,我们仍然以A、B 两个线程为例:
    1. A、B 线程同时进入了第一个if 判断
    2. A 首先进入synchronized 块,由于instance 为null,所以它执行instance = new Singleton();
    3. 由于JVM 内部的优化机制,JVM 先画出了一些分配给Singleton 实例的空白内存,并赋值给instance成员(注意此时JVM 没有开始初始化这个实例)
    然后A 离开了synchronized 块。
    4. B 进入synchronized 块,由于instance 此时不是null,因此它马上离开了synchronized 块并将结果返回给调用该方法的程序。
    5. 此时B 线程打算使用Singleton 实例,却发现它没有被初始化,于是错误发生了。

    3.内部类

    public class Singleton {
               
            private Singleton(){        
                
         }        
           
        private class SingletonHoledr(){        
            private static Singleton instance = new Singleton();        
         }        
           
        private static Singleton getInstance(){        
            return SingletonHoledr.instance;        
         }        
    } 
  • 相关阅读:
    Android 自定义Dialog中加EditText弹不出键盘跟Dialog遮挡键盘的问题
    上周热点回顾(8.28-9.3)团队
    云计算之路-阿里云上-新车限行:新购服务器无法访问任何远程25端口团队
    上周热点回顾(8.21-8.27)团队
    云计算之路-阿里云上-容器难容:自建docker swarm集群遭遇无法解决的问题团队
    上周热点回顾(8.14-8.20)团队
    上周热点回顾(8.7-8.13)团队
    上周热点回顾(7.31-8.6)团队
    上周热点回顾(7.24-7.30)团队
    故障公告:docker swarm集群“群龙无首”造成部分站点无法访问团队
  • 原文地址:https://www.cnblogs.com/yuyutianxia/p/3833429.html
Copyright © 2011-2022 走看看