AtomicInteger用于有限序列生成

时间:2010-06-02 17:25:50

标签: java atomic

我们如何使用AtomicInteger进行有限的序列生成,假设序列号必须在1到60之间。一旦序列达到60,它必须从1开始。我写了这段代码虽然不太确定这是否是线程安全的不是吗?

public int getNextValue()
{
 int v;
 do
 {
   v = val.get();
   if ( v == 60)
   {
    val.set(1);
   }
 }
  while (!val.compareAndSet(v , v + 1));
   return v + 1;
  }

6 个答案:

答案 0 :(得分:14)

你可以做到

return val.getAndIncrement() % 60;

除非你担心超过整数最大值(2147483647)。如果这是一个问题,您可以查看getAndIncrement实现:

public final int getAndIncrement() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return current;
    }
}

您需要更改的是int next...行,如:

int next = (current + 1) % 60;

糟糕。这循环通过0-> 59。您需要1-> 60,因此请在返回值中添加一个以获得所需的结果。

答案 1 :(得分:5)

您可以使用Java 8在一行中完成此操作。

AtomicInteger counter = new AtomicInteger();

public int getNextValue() {
    return counter.updateAndGet(n -> (n >= 60) ? 1 : n + 1);
}

答案 2 :(得分:1)

如果您创建方法synchronized,那么只要val无法访问其他地方,它就会是线程安全的。然而,这种方法有点麻烦,我将其重写如下:

public synchronized int getNextValue() {
    val.compareAndSet(60, 0); // Set to 0 if current value is 60.
    return val.incrementAndGet();
}

这给出1直到60回包含。如果您确实需要1到59,那么请将60替换为59

答案 3 :(得分:0)

不,它不是线程安全的 - 你不应该在一个循环中调用set

int value, next;
do {
    value = val.get();
    next = (value == 60) ? 1 : (value + 1);
} while (!val.compareAndSet(value, next);
return next;

答案 4 :(得分:0)

在这里使用AtomicInteger的任何特殊原因而不仅仅是一个简单的同步方法?

如下简单的事情:

private int val=1;

public synchronized int getNextValue() {
 int v=val;
 val = (val==60) ? 1 : (val+1); 
 return v;
}

答案 5 :(得分:0)

快速回答,不是线程安全的。测试和集合需要是原子的,除非你使整个方法同步。注意val.get()和v的测试不是原子的。如果线程在v = val.get()之后产生,你将得到两个具有相同序列号的调用。

此外,如果compareAndSet失败,您永远不会更改值,它将是一个无限循环。

AtomicInteger有一个    getAndIncrement() 呼叫。这将为您提供一个清洁的价值回报。

滚动有点棘手。一种解决方案是修改返回值。像这样:

int v = val.getAndIncrement();
return (v % 60) + 1;

由于每个线程都有v的本地副本,我们可以安全地对其进行一些数学运算并返回值。如果你遇到溢出,有一个问题。根据您生成序列号的频率,这可能是也可能不是问题。