简体   繁体   中英

What is the best way to ensure concurrent object calls without locking

I have the following objects:

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

This approach probably has a race condition where one thread executes isActive() and another load() . Although it operates on reference and the object state is not changed.

What is the best solution to support such concurrency? I would like to avoid syncronized on methods, and also read-write lock.

Maybe AtomicReference or volatile ? Or maybe it would be better to return only reference to the data itself without proxy methods? So no need for locking at all, and all the usage logic is outside this service?

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

 public MyDataAddOps getData(){
    return data;
  }
 }

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM