使用Java的Atomic类进行模块化增量

Mar*_*ark 2 java modulo atomicity

我很惊讶Java的AtomicInteger和AtomicLong类没有模块化增量的方法(因此在达到限制后值会回绕到零).

我想我必须遗漏一些明显的东西.最好的方法是什么?

例如,我想在线程之间共享一个简单的int,我希望每个线程能够增加它,比如mod 10.

我可以创建一个使用同步/锁的类,但有更好,更简单的方法吗?

Col*_*inD 13

你读它时只需修改10的值吗?

public class AtomicWrappingCounter {
  private final AtomicLong counter = new AtomicLong();
  private final int max;

  public AtomicWrappingCounter(int max) {
    this.max = max;
  }

  public int get() {
    return (int) (counter.get() % max);
  }

  public int incrementAndGet() {
    return (int) (counter.incrementAndGet() % max);
  }
}
Run Code Online (Sandbox Code Playgroud)

显然,如果你可能会Long.MAX_VALUE多次增加这个计数器,你就不能使用这种方法,但是9 quintillion很多时候需要递增(大约292年,每纳秒1个!).


cak*_*aww 10

在Java 8,你可以使用getAndUpdate(和updateAndGet中)AtomicInteger

例如,如果我们想要一个计数器在每次达到 10 时都归零。

AtomicInteger counter = new AtomicInteger(0);

// to get & update
counter.getAndUpdate(value -> (value + 1) % 10)
Run Code Online (Sandbox Code Playgroud)


mat*_*t b 9

我认为最简单的方法是自己构建一个包装计数器,它将它的值存储在AtomicInteger中,类似于

public class AtomicWrappingCounter {
    private AtomicInteger value;
    private final int max;

    public AtomicWrappingCounter(int start, int max) {
        this.value = new AtomicInteger(start);
        this.max = max;
    }

    public int get() {
        return value.get();
    }

    /* Simple modification of AtomicInteger.incrementAndGet() */
    public int incrementAndGet() {
        for (;;) {
            int current = get();
            int next = (current + 1) % max;
            if (value.compareAndSet(current, next))
                return next;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么不AtomicInteger提供这样的东西呢?谁知道,但我认为并发框架作者的意图是提供一些构建块,您可以使用它们来更好地创建自己的更高级别的功能.

  • 是的,所以在这种情况下你无论如何都不想使用原子类,这种情况基本上否定了这个问题的核心。不过,这是值得了解的好信息。 (2认同)

Mic*_*rdt 4

synchronized在你的方法中添加修饰符或块有什么困难addModular()

这些类不具有此功能的原因Atomic是它们基于当前 CPU 提供的特定原子硬件指令,并且如果不诉诸锁定或其他更复杂且可能效率低下的算法,则无法实现模块化算术马特建议。