【问题标题】:How to decrement one field and increment another field atomically in java using concurrency classesjava - 如何使用并发类在Java中原子地减少一个字段并增加另一个字段
【发布时间】:2017-12-12 05:40:21
【问题描述】:

我有一个状态机 - 待处理和已完成 - AtomicLong(线程)。我需要以原子方式递减挂起和递增完成

private final AtomicLong pending = new AtomicLong();
private final AtomicLong completed = new AtomicLong();

void markComplete() {
  this.pending.decrementAndGet();
  this.completed.incrementAndGet();
}

我可以通过使用块进行同步来使这个原子化。但这似乎破坏了使用并发对象的使用。

synchronized void markComplete() {
  this.pending.decrementAndGet();
  this.completed.incrementAndGet();
}

我想知道是否有更好的方法来做到这一点?

谢谢你帮助我。

【问题讨论】:

  • 一个只有两个原子语句的同步块在我看来并不是一个大的性能问题。你有什么问题?
  • 这些值是否必须为long?如果两个int 值就足够了,您可以通过执行((long) completed) << 32 + pending 将它们打包到long 中。递增完成意味着添加 1L
  • 不需要按位运算来更新状态:long current = this.pending.addAndGet(1L<<32-1); long currentCompleted = current >> 32; long currentPending = current & 0xffffffff;。更改共享状态后发生按位操作
  • 简单地说 - 你不能。您需要synchronized(或其他类型的锁)或将它们作为AtomicReference<Holder> 的一部分,其中Holder 封装了这两个值
  • 但问题仍然存在——你能用int代替吗?在前 32 位表示增量和后 32 位减量的意义上,您可能会使用 LongAdder 的肮脏技巧逃脱

标签: java concurrency atomic


【解决方案1】:

如果pendingcomplete 适合int 范围(并且只要在您调用markComplete() 时挂起大于零),您可以按照以下方式进行操作:

private final AtomicLong pendingAndComplete = new AtomicLong();

void markComplete() {
  this.pendingAndComplete.addAndGet(1L<<32-1); // this is atomic
}
void markPending() {
  this.pendingAndComplete.incrementAndGet(); // this is atomic
}

void doSomething() {
  long current = this.pendingAndComplete.get(); // this fetches the current state atomically

  int currentCompleted = (int)(current >> 32);
  int currentPending = (int) current;
}

【讨论】:

    【解决方案2】:

    不要更新currentPending,因为它是可推导的。让它固定并使用它:

    public long getCurrentPending() {
        return currentPending.get() - completed.get();
    }
    

    当你添加项目而不破坏任何东西时,你总是可以增加currentPending

    【讨论】:

    • 感谢您的快速回复。但是对象是一个状态机。字段 pendingcompleted 都是 AtomicLong 类型。这些字段的状态对状态机很重要。为了清楚起见,我将修改帖子。
    • @SudhirR 我不认为你理解我的意思:你可以使用这种方法而不是直接访问该字段(而不是更新currentPending)。
    【解决方案3】:

    并发对象仅用于使一个值线程安全。如果您想在多个值上具有并发性,则必须使用锁定(如同步)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-11
      • 1970-01-01
      • 2017-05-24
      • 2023-03-16
      • 2011-05-20
      • 2021-06-25
      • 1970-01-01
      相关资源
      最近更新 更多