Java:使代码块原子化

标签 java concurrency race-condition

假设我有这段 Java 代码

我想知道是否有一种无锁机制可以使突出显示的代码片段成为原子的。我想避免当有人调用 fetchSomeThing() 时,我正处于 BlockX 的中间,并且 fetchSomeThing() 正在从新的副本中查找A 但 B 和 C 的旧副本。

public class MyClass
{
   private volatile Map a, b, c; 

   public void refresh()
   {
      Map a_ = loadA();   
      Map b_ = loadB();
      Map c_ = loadC();

      //I want to make the following block atomic
      // call it Block X
      {
         this.a = a_;
         this.b = b_;
         this.c = c_;
      }
   }

   public String fetchSomeThing()
   {
       // some joint operations on this.a, this.b and this.c
   }
}

我能想到的唯一方法是将其分成两个类并将 a、b、c 包装在一个对象中。

但是非常麻烦。有没有更好的办法?

public class MyShadowClass
{
   private Map a, b, c; 
   public MyShadowClass()
   {
      init();
   }

   public void init()
   {
      Map a_ = loadA();   
      Map b_ = loadB();
      Map c_ = loadC();

      this.a = a_;
      this.b = b_;
      this.c = c_;
   }

   public String fetchSomeThing()
   {
       // some joint operations on this.a, this.b and this.c
   }
}

public class MyClass
{
   private volatile MyShadowClass shadow; 
   public void refresh()
   {
      MyShadowClass tempShadow = new MyShadowClass();
      shadow = tempShadow; 
   }

   public String fetchSomeThing()
   {
      return shadow.fetchSomeThing();
   }

}

最佳答案

简单地创建一个保持当前有效状态的复合对象。然后,您可以使用 AtomicReference 来管理当前状态:

 private AtomicReference<Thing> currentThing = new AtomicReference<Thing>();

 public Thing getThing() {
      while (true) {
          Thing result = currentThing.get();
          if (result != null)
              return result;
          result = buildThing();
          if (currentThing.compareAndSet(null, result);
              return result;
      }
 }

 private Thing buildThing() {
      // whatever, only important thing is that this creates
      // a new and valid instance of Thing
 }

 public void refresh() {
      Thing freshThing = buildThing();
      currentThing.set(freshThing);
 }

如果您可以确保只有一个线程写入该字段,或者您不特别关心在刷新()和初始时获取相同的实例,那么您可以简单地将“currentThing”声明为正常的但 volatile 字段。 get 正在同时执行。

关于Java:使代码块原子化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26633957/

相关文章:

android - Jetpack 撰写 : calling action inside LauchedEffect blocks UI anyway

java - 何时强制执行对 UI 线程中字段的原子性或 volatile 访问?

java - 用于设计可扩展 Web 服务的模式

javascript - 使用 fetch api Redux 异步请求

php - 我该如何解决这个 Solr/MySQL 竞争条件?

java - Pdfbox 签名 - saveIncremental 与 saveIncrementalForExternalSigning

java - final 字段真的能防止 Java 中的可变性吗?

java - Android:从mysql获取数据时doInBackground出错

java - YAML 值未正确返回

javascript - 哪种方式可以尽可能直接地从 dataToURL-image 字符串创建 Canvas 模式?