在没有锁定的情况下确保并发对象调用的最佳方法是什么

时间:2015-07-14 19:23:45

标签: java multithreading concurrency

我有以下对象:

// this class is immutable, acts like container for several properties.
public class MyDataAddOps{
    private final boolean isActive;
    private final Map<String,Object> additionalProps;

    public MyDataAddOps(boolean isActive, Map<String,Object> additionalProps){
       this.isActive = isActive;
       this.additionalProps = additionalProps;
    }

   public boolean isActive(){return isActive;}
   public Map<String,Object> getAdditionalProps(){ return additionalProps;}
}

// this class acts as "spring" bean that calls load on construction,
//  and then another scheduler bean calls the load per some cron expression (once a minute for example) 
public class MyDataAddOpsService{
   private MyDataAddOps data;

   // this method will be executed periodically outside
   // via some spring quartz for example
   // the quartz is not re-entrant  
   public void load(){
      // opens some defined file and returns content string 
      String fileData = getFileContent(); 
      boolean isActive = getIsActive(fileData);
      Map<String, Object> props = getProps(fileData);
      data = new MyDataAddOps(isActive, props);
   }

  // This method is executed by many workers threads inside the application
  public boolean isActive(){
     return data.isActive();
  }

  public final Map<String, Object> getProps(){
      return data.getAdditionalProps();
  } 
 }

这种方法可能存在竞争条件,其中一个线程执行isActive()而另一个load()。虽然它在引用上运行但对象状态没有改变。

支持此类并发的最佳解决方案是什么?我想避免同步方法,还有读写锁。

可能是AtomicReference还是volatile?或者,如果没有代理方法,只返回对数据本身的引用会更好?所以根本不需要锁定,并且所有使用逻辑都在此服务之外?

 public class MyDataAddOpsService{
   private MyDataAddOps data;
   public void load(){
     ....
     data = new MyDataAddOps(isActive, props);
   }

 public MyDataAddOps getData(){
    return data;
  }
 }

1 个答案:

答案 0 :(得分:5)

Your code has yet to grow towards having a race condition; currently it contains something much more severe, which is a data race. Publishing a reference across threads without inducing a happens before relationship between the write and the future reads means that the reader can see the data object in a partially initialized, inconsistent state. Your proposal of a solution does not help with that.

Once you make the data field volatile, only then will you have a race condition between one thread first reading the data reference, then another thread updating the data reference, then the first thread reading isActive from the old data. This may actually be a benign case for your logic.