如果多个线程调用“incrementCount”方法,以下代码是否会导致竞争条件问题?
public class sample {
private AtomicInteger counter = new AtomicInteger(0);
public int getCurrentCount {
int current = counter.getAndIncrement();
if (counter.compareAndSet(8, 0)) current = 0;
return current;
}
}
如果它导致竞争条件,除了使用synchronized关键字之外,还有什么可能的解决方案?
答案 0 :(得分:3)
你可能不想让计数器超过8,这是行不通的。有竞争条件。
看起来你想要一个mod 8计数器。最简单的方法是单独使用AtomicInteger并使用类似
的内容int current = counter.getAndIncrement() & 7;
(这是% 8
的固定和优化版本)。对于mod 8的计算或任何其他2的幂,它可以完美地工作,对于其他数字,你需要% N
并且遇到int溢出到负数的问题。
直接解决方案如下
public int getCurrentCount {
while (true) {
int current = counter.get();
int next = (current+1) % 8;
if (counter.compareAndSet(current, next))) return next;
}
}
这是关于getAndIncrement()
本身的工作原理,只是稍作修改。
答案 1 :(得分:2)
是的,它可能没有你想要的(有一种竞争条件)。
getAndIncrement()
并收到8 getAndIncrement()
并收到9 compareAndSet
,但值不是8 compareAndSet
,但值不是8 如果没有溢出的风险,你可以做类似
的事情return counter.getAndIncrement() % 8;
依靠那些不会溢出的东西对我来说似乎是一个糟糕的主意,我可能会粗略地做你做的事情,但让方法为synchronized
。
答案 2 :(得分:1)
基于getAndIncrement()的代码
public int getCurrentCount() {
for(;;) {
int courrent = counter.get();
int next = current + 1;
if (next >= 8) next = 0;
if (counter.compareAndSet(current, next))
return current;
}
}
然而,在您的情况下,更简单的实现是
public int getCurrentCount() {
return counter.getAndIncrement() & 0x7;
}
答案 3 :(得分:1)
你想要达到什么目的?即使您使用ajoobe或maartinus提出的修复程序,您也可以得到不同的线程获得相同的答案 - 考虑同时运行20个线程。我在这里看到这个“计数器”时没有看到任何有趣的意义 - 你也可以选择0到8之间的随机数。
答案 4 :(得分:0)
我认为你想要的是一个0到7的计数器形式。
如果是这种情况,则可能发生竞争条件,并且计数器的值可以变为9。
除非您可以使用%soln。正如其他人所说,你必须使用synchronized。