我很惊讶Java的AtomicInteger和AtomicLong类没有模块化增量的方法(因此在达到限制后值会回绕到零)。
我认为我必须遗漏一些明显的东西。最好的方法是什么?
例如,我想在线程之间共享一个简单的int,我希望每个线程能够增加它,比如说mod 10.
我可以创建一个使用同步/锁定的类,但有更好,更简单的方法吗?
答案 0 :(得分: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);
}
}
显然,如果你可以将这个计数器增加超过Long.MAX_VALUE
次,你就不能使用这种方法,但是9次提升是很多次增加(大约292年,每纳秒1次! )。
答案 1 :(得分: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;
}
}
}
为什么AtomicInteger
不提供这样的东西?谁知道,但我认为并发框架作者的意图是提供一些构建块,您可以使用它们来更好地创建自己的更高级别的功能。
答案 2 :(得分:4)
在synchronized
方法中添加addModular()
修饰符或块有什么困难?
Atomic
类不具备此功能的原因是它们基于当前CPU提供的specific atomic hardware instructions,并且无需借助锁定或其他操作的人无法实现模块化算法更复杂,效率最低的算法,如matt所建议的算法。
答案 3 :(得分:2)
在Java 8中,您可以在updateAndGet
中使用getAndUpdate(和AtomicInteger
)。
例如,如果我们想让一个计数器在每次达到10时都归零。
AtomicInteger counter = new AtomicInteger(0);
// to get & update
counter.getAndUpdate(value -> (value + 1) % 10)
答案 4 :(得分:1)
我很惊讶Java的AtomicInteger和AtomicLong类没有模块化增量的方法。
当标准课程不包括“花里胡哨”以支持各种不寻常的用例时,不要感到惊讶。设计师必须在它们包含的内容和它们不包含的内容上划一条线。趋势是支持常见用例和不可能以任何其他方式支持的用例。在这种情况下,这些标准都不适用。