zoukankan      html  css  js  c++  java
  • 多线程下真正的单例

    首先,讨论一下单例对象的初始化同步。单例模式的通常处理方式是,在对象中有一个静态成员变量,其类型就是单例类型本身;如果该变量为null,则创建该单例类型的对象,并将该变量指向这个对象;如果该变量不为null,则直接使用该变量。
      其过程如下面代码所示:

    Java代码  
    public class GlobalConfig {  
        private static GlobalConfig instance = null;  
        private Vector properties = null;  
        private GlobalConfig() {  
          //Load configuration information from DB or file  
          //Set values for properties  
        }  
        public static GlobalConfig getInstance() {  
          if (instance == null) {  
            instance = new GlobalConfig();  
          }  
          return instance;  
        }  
        public Vector getProperties() {  
          return properties;  
        }  
      }  
    

      

     这种处理方式在单线程的模式下可以很好的运行;但是在多线程模式下,可能产生问题。如果第一个线程发现成员变量为null,准备创建对象;这是第二 个线程同时也发现成员变量为null,也会创建新对象。这就会造成在一个JVM中有多个单例类型的实例。如果这个单例类型的成员变量在运行过程中变化,会 造成多个单例类型实例的不一致,产生一些很奇怪的现象。例如,某服务进程通过检查单例对象的某个属性来停止多个线程服务,如果存在多个单例对象的实例,就 会造成部分线程服务停止,部分线程服务不能停止的情况。
      1.2 单例对象的属性更新 
      通常,为了实现配置信息的实时更新,会有一个线程不停检测配置文件或配置数据库的内容,一旦发现变化,就更新到单例对象的属性中。在更新这些信 息的时候,很可能还会有其他线程正在读取这些信息,造成意想不到的后果。还是以通过单例对象属性停止线程服务为例,如果更新属性时读写不同步,可能访问该 属性时这个属性正好为空(null),程序就会抛出异常。
      解决方法 
      2.1 单例对象的初始化同步
      对于初始化的同步,可以通过如下代码所采用的方式解决。

    Java代码  
    public class GlobalConfig {  
        private static GlobalConfig instance = null;  
        private Vector properties = null;  
        private GlobalConfig() {  
          //Load configuration information from DB or file  
          //Set values for properties  
        }  
        private static synchronized void syncInit() {  
          if (instance == null) {  
            instance = new GlobalConfig();  
          }  
        }  
        public static GlobalConfig getInstance() {  
          if (instance == null) {  
            syncInit();  
          }  
          return instance;  
        }  
        public Vector getProperties() {  
          return properties;  
        }  
      } 
    

      

     

     这种处理方式虽然引入了同步代码,但是因为这段同步代码只会在最开始的时候执行一次或多次,所以对整个系统的性能不会有影响。
        2.2 单例对象的属性更新同步 
      为了解决第2个问题,有两种方法:
      1,参照读者/写者的处理方式 
      设置一个读计数器,每次读取配置信息前,将计数器加1,读完后将计数器减1.只有在读计数器为0时,才能更新数据,同时要阻塞所有读属性的调用。代码如下。

    Java代码  
    public class GlobalConfig {  
     private static GlobalConfig instance;  
     private Vector properties = null;  
     private boolean isUpdating = false;  
     private int readCount = 0;  
     private GlobalConfig() {  
       //Load configuration information from DB or file  
          //Set values for properties  
     }  
     private static synchronized void syncInit() {  
      if (instance == null) {  
       instance = new GlobalConfig();  
      }  
     }  
     public static GlobalConfig getInstance() {  
      if (instance==null) {  
       syncInit();  
      }  
      return instance;  
     }  
     public synchronized void update(String p_data) {  
      syncUpdateIn();  
      //Update properties  
     }  
     private synchronized void syncUpdateIn() {  
      while (readCount > 0) {  
       try {  
        wait();  
       } catch (Exception e) {  
       }  
      }  
     }  
     private synchronized void syncReadIn() {  
      readCount++;  
     }  
     private synchronized void syncReadOut() {  
      readCount--;  
      notifyAll();  
     }  
     public Vector getProperties() {  
      syncReadIn();  
      //Process data  
      syncReadOut();  
      return properties;  
     }  
      }  
    

      

    更多详情请关注 http://www.cnblogs.com/baixingqiang/
  • 相关阅读:
    go基础1:Hello world与变量声明
    linux 根据端口号查看占用进程的pid
    攻防世界web新手练习区WP
    github下载慢解决方法
    玩转MSFconsole
    中国蚁剑AntSword安装
    burpsuite出现Payload set 1: Invalid number settings的解决办法
    在同一台电脑上同时安装Python2和Python3
    msf转移木马进程
    网站后台爆破工具:WebCrack
  • 原文地址:https://www.cnblogs.com/baixingqiang/p/5770286.html
Copyright © 2011-2022 走看看