码迷,mamicode.com
首页 > 编程语言 > 详细

多线程下真正的单例

时间:2016-08-14 16:12:21      阅读:199      评论:0      收藏:0      [点我收藏+]

标签:

首先,讨论一下单例对象的初始化同步。单例模式的通常处理方式是,在对象中有一个静态成员变量,其类型就是单例类型本身;如果该变量为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/p/5770286.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!