java并发:轻量级非阻塞信号量?

发布于 2024-10-26 03:21:35 字数 1290 浏览 6 评论 0原文

我遇到一种情况,我想执行一次回调。为了便于论证,我们假设它看起来像这样:

final X once = new X(1);
Runnable r = new Runnable() {
    @Override public void run() {
        if (once.use())
           doSomething();
    }
}

其中 X 是具有以下行为的并发对象:

  • 构造函数:X(int N) -- 分配 N 使用许可

  • boolean use():如果至少有 1 个使用许可,则使用其中一个并返回 true。否则返回 false。此操作对于多个线程来说是原子的。

我知道我可以使用 java.util。 concurrent.Semaphore 为此,但我不需要它的阻塞/等待方面,并且我希望这是一次性使用的东西。

AtomicInteger 看起来不够,除非我做了类似的事情

class NTimeUse {
   final private AtomicInteger count;
   public NTimeUse(int N) { this.count = new AtomicInteger(N); }
   public boolean use() {
       while (true)
       {
          int n = this.count.get();
          if (n == 0)
             return false;
          if (this.count.compareAndSet(n, n-1))
             return true;
       }
   }

,并且我对 while 循环感到恶心。

CountDownLatch 不起作用,因为 countDown() 方法 没有返回值,并且不能使用 getCount() 以原子方式执行。

我应该只使用 Semaphore 还是有更合适的类?

I have a situation where I have a callback that I want to execute once. For the sake of argument let's say it looks like this:

final X once = new X(1);
Runnable r = new Runnable() {
    @Override public void run() {
        if (once.use())
           doSomething();
    }
}

where X is some concurrent object with the following behavior:

  • constructor: X(int N) -- allocates N use permits

  • boolean use(): If there is at least 1 use permit, consume one of them and return true. Otherwise return false. This operation is atomic with respect to multiple threads.

I know I can use java.util.concurrent.Semaphore for this, but I don't need the blocking/waiting aspect of it, and I want this to be a one-time use thing.

AtomicInteger doesn't look sufficient unless I do something like

class NTimeUse {
   final private AtomicInteger count;
   public NTimeUse(int N) { this.count = new AtomicInteger(N); }
   public boolean use() {
       while (true)
       {
          int n = this.count.get();
          if (n == 0)
             return false;
          if (this.count.compareAndSet(n, n-1))
             return true;
       }
   }

and I feel queasy about the while loop.

CountDownLatch won't work, because the countDown() method has no return value and can't be executed atomically w/r/t getCount().

Should I just use Semaphore or is there a more appropriate class?

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

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

发布评论

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

评论(3

计㈡愣 2024-11-02 03:21:41

在单个许可的情况下,您可以使用 AtomicBoolean

final AtomicBoolean once = new AtomicBoolean(true);
Runnable r = new Runnable() {
    @Override public void run() {
        if (once.getAndSet(false))
           doSomething();
    }
}

如果您需要多个许可,请使用 compareAndSet() 解决方案。不用担心循环,getAndIncrement() 在幕后的工作方式相同。

In the case of single permit you can use AtomicBoolean:

final AtomicBoolean once = new AtomicBoolean(true);
Runnable r = new Runnable() {
    @Override public void run() {
        if (once.getAndSet(false))
           doSomething();
    }
}

If you need many permits, use your solution with compareAndSet(). Don't worry about the loop, getAndIncrement() works the same way under the cover.

む无字情书 2024-11-02 03:21:41

是的。 AtomicInteger 是非阻塞的。您可以使用 getAndDecrement()。

您可以使用类似的方法,

if(counter.getAndDecrement() > 0) {
   // something
} else {
   counter.set(0);
}

只要您在递减和集合之间不调用它二十亿次,这就会起作用。也就是说,您需要有 20 亿个线程在这两个语句之间停止。

同样,您可以使用 AtomicLong 来进行额外的偏执。

yes. AtomicInteger is non-blocking. You can use getAndDecrement().

You can use something like

if(counter.getAndDecrement() > 0) {
   // something
} else {
   counter.set(0);
}

This will work provided you don't call it two billion times between the decrement and the set. i.e. you would need to have two billion threads stop between these two statements.

Again you can use AtomicLong for extra paranoia.

╰◇生如夏花灿烂 2024-11-02 03:21:41
// This implements an unfair locking scheme:
while ( mayContinue() ) {
    // acquire the permit and check if it was legally obtained
    if ( counter.decrementAndGet() > 0 )
        return true;
    // return the illegally acquired permit
    counter.incrementAndGet();
}
return false;

如果您发现非法获得许可,则将计数器设置回零,从而在另一个线程释放许可时产生竞争条件。这只适用于最多 2 或 3 个线程的情况。如果您有更多,则需要添加一些其他退避或锁定机制。

// This implements an unfair locking scheme:
while ( mayContinue() ) {
    // acquire the permit and check if it was legally obtained
    if ( counter.decrementAndGet() > 0 )
        return true;
    // return the illegally acquired permit
    counter.incrementAndGet();
}
return false;

Setting the counter back to zero if you discover the permit was illegally obtained creates a race condition when another thread releases a permit. This only works for situations where there are 2 or 3 threads at most. Some other backoff or latching mechanism needs to be added if you have more.

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