用于有限序列生成的 AtomicInteger

发布于 2024-09-04 07:10:45 字数 296 浏览 3 评论 0原文

我们如何使用 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;
  }

How can we use AtomicInteger for limited sequence generation say the sequence number has to be between 1 to 60. Once the sequence reaches 60 it has to start again from 1. I wrote this code though not quite sure wether this is thread safe or not?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

安静 2024-09-11 07:10:45

从 Java 8 开始,您可以使用 AtomicInteger.updateAndGet

return val.updateAndGet(n -> (n >= 60) ? 1 : n + 1);

另一种选择是简单地执行...

return val.getAndIncrement() % 60;

...除非您担心超过整数 max-值(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 以获得所需的结果。

As of Java 8, you can use AtomicInteger.updateAndGet:

return val.updateAndGet(n -> (n >= 60) ? 1 : n + 1);

Another alternative would be to simply do...

return val.getAndIncrement() % 60;

...unless you're concerned with exceeding the integer max-value (2147483647). If that is a concern, you could have a look at the getAndIncrement implementation:

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

All you need to change is the int next... line to something like:

int next = (current + 1) % 60;

Oops. This loops through 0->59. You needed 1->60, so add one to the return-value to get the desired result.

分开我的手 2024-09-11 07:10:45

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

AtomicInteger counter = new AtomicInteger();

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

You can do this in a single line using Java 8.

AtomicInteger counter = new AtomicInteger();

public int getNextValue() {
    return counter.updateAndGet(n -> (n >= 60) ? 1 : n + 1);
}
攒一口袋星星 2024-09-11 07:10:45

如果您使方法同步,那么只要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

If you make the method synchronized then it will be threadsafe as long as the val is nowhere else accessed. The approach is however a bit cumbersome, I'd rewrite it as follows:

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

This gives 1 until with 60 back inclusive. If you actually need 1 until with 59, then replace 60 by 59.

终止放荡 2024-09-11 07:10:45

在这里使用 AtomicInteger 而不仅仅是简单的同步方法有什么特殊原因吗?

像下面这样简单的事情怎么样:

private int val=1;

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

Any particular reason to use AtomicInteger here rather than just a simple synchronized method?

How about something simple like the following:

private int val=1;

public synchronized int getNextValue() {
 int v=val;
 val = (val==60) ? 1 : (val+1); 
 return v;
}
蛮可爱 2024-09-11 07:10:45

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

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

No, it's not thread safe - you shouldn't call set inside a cycle:

int value, next;
do {
    value = val.get();
    next = (value == 60) ? 1 : (value + 1);
} while (!val.compareAndSet(value, next);
return next;
孤城病女 2024-09-11 07:10:45

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

另外,如果 CompareAndSet 失败,您永远不会更改值,这将是一个无限循环。

原子整数有一个
getAndIncrement()
称呼。这将为您带来一个干净的返回值。

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

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

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

Quick answer, not thread safe. The test and set need to be atomic, unless you make the whole method synchronized. Note the val.get() and the test of v are not atomic. If the thread yields after v = val.get() you'll get two calls with the same sequence number.

Also, if the compareAndSet fails you never change the values, it'll be an infinite loop.

AtomicInteger has a
getAndIncrement()
call. That will get you a clean value to return.

The rolling is a bit trickier. One solution is to mod the return value. Something like so:

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

Since each thread has a local copy of v we can safely do some math on it and return the value. There is one sticking point if you get an overflow. Depending on how often you generate a sequence number this may or may not be an issue.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文