【问题标题】:What is the best way to ensure concurrent object calls without locking确保并发对象调用而不锁定的最佳方法是什么
【发布时间】:2015-07-15 03:56:44
【问题描述】:

我有以下物品:

// 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()。虽然它对引用进行操作并且对象状态没有改变。

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

也许是AtomicReferencevolatile?或者最好只返回对数据本身的引用而不使用代理方法?所以根本不需要加锁,所有的使用逻辑都在这个服务之外?

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

 public MyDataAddOps getData(){
    return data;
  }
 }

【问题讨论】:

  • MyDataAddOps 绝对不是一成不变的。您担心线程安全问题是对的,但它们远远超出了您所指出的问题。使这个代码线程安全可能超出了本论坛的范围。

标签: java multithreading concurrency


【解决方案1】:

您的代码尚未发展为具有竞争条件;目前它包含更严重的东西,即数据竞赛。跨线程发布引用而不引起写入和未来读取之间的发生之前关系意味着读者可以看到处于部分初始化的不一致状态的数据对象。您提出的解决方案对此无济于事。

一旦你创建了data 字段volatile,只有那么在一个线程首先读取data 引用,然后另一个线程更新data 引用之间会有竞争条件,然后第一个线程从旧数据中读取isActive。对于您的逻辑而言,这实际上可能是一个良性案例。

【讨论】:

  • 谢谢,但是如果我让这个对象完全不可变。没有设置器(只有构造器)和获取器(用于道具将返回地图的副本)。一旦某个线程有引用,它就可以使用它。同时服务状态将更改为另一个引用。从我的逻辑角度来看,这没关系。新线程将获得更新的引用。因此不需要锁定。我错过了什么吗?
  • 是的,我相信您不需要锁定。只需创建共享变量volatile
  • BTW 地图获取者不需要复制地图,只需返回一个 immutableMap 包装器。您可以在构建时包装地图,然后将相同的实例返回给每个人。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 2010-09-30
  • 2020-09-06
相关资源
最近更新 更多