【发布时间】:2019-12-01 14:04:35
【问题描述】:
我有一个将值存储为 AtomicInteger 的 Counter 类。该类应该是线程安全的。我有方法boolean consume(int number),如果counter >= number,应该递减计数器并返回true,如果counter < number,不应该更改计数器并返回false
class Counter {
AtomicInteger counter = new AtomicInteger(initialValue);
boolean consume(int number) {
counter.accumulateAndGet(number, (prev, next) -> {
if (number <= prev) {
return prev - number;
} else {
// not modify the previous number;
return prev;
}
});
return ???
}
}
而且我不知道该功能是否适用。我找到了以下解决方案
boolean consume(int number) {
AtomicBoolean result = new AtomicBoolean(false);
counter.accumulateAndGet(number, (prev, next) -> {
if (number <= prev) {
result.set(true);
return prev - number;
// function applied
} else {
result.set(false);
// not modify the previous number;
return prev;
}
});
return result.get();
}
但是accumulateAndGetsais的javadoc:
该功能应该没有副作用,因为它可以重新应用 当尝试更新由于线程之间的争用而失败时。
所以,我的解决方案有副作用。使用安全吗?如果不是,我怎样才能得到相同的结果?
【问题讨论】:
-
我会说是的,因为副作用是幂等的:如果第一次更新失败并且完成了新的尝试,结果将被正确更新。如果你在二元运算符中增加了一个外部值,那就另当别论了。
-
我强烈建议你不使用这种方法会更清楚。仅将标准
compareAndSet循环写为包含两个出口的for (;;)。如果您迫切需要单入口单出口 (SESE) 样式,即使是标准循环也可以保留足够的本地信息以确定其走向。
标签: java concurrency atomicinteger