简体   繁体   English

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

[英]java concurrency: lightweight nonblocking 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: 其中X是一些具有以下行为的并发对象:

  • constructor: X(int N) -- allocates N use permits 构造函数:X(int N) - 分配N个使用许可

  • boolean use() : If there is at least 1 use permit, consume one of them and return true. boolean use() :如果至少有1个use permit,则使用其中一个并返回true。 Otherwise return false. 否则返回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. 我知道我可以使用java.util.concurrent.Semaphore ,但我不需要它的阻塞/等待方面,我希望这是一次性使用的东西。

AtomicInteger doesn't look sufficient unless I do something like 除非我做类似的事情,否则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;
       }
   }

and I feel queasy about the while loop. 而我对while循环感到不安。

CountDownLatch won't work, because the countDown() method has no return value and can't be executed atomically w/r/t getCount(). CountDownLatch将不起作用,因为countDown()方法没有返回值,并且不能以原子方式执行w / r / t getCount()。

Should I just use Semaphore or is there a more appropriate class? 我应该只使用信号量还是有更合适的类?

In the case of single permit you can use AtomicBoolean : 在单一许可的情况下,您可以使用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() . 如果您需要许多许可,请使用compareAndSet()解决方案。 Don't worry about the loop, getAndIncrement() works the same way under the cover. 不要担心循环, getAndIncrement()在封面下的工作方式相同。

yes. 是。 AtomicInteger is non-blocking. AtomicInteger是非阻塞的。 You can use getAndDecrement(). 您可以使用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. 如果你在减量和集合之间没有调用它20亿次,这将有效。 ie you would need to have two billion threads stop between these two statements. 即你需要在这两个语句之间停止20亿个线程。

Again you can use AtomicLong for extra paranoia. 你可以再次使用AtomicLong来获得额外的偏执狂。

// 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. 这仅适用于最多有2个或3个线程的情况。 Some other backoff or latching mechanism needs to be added if you have more. 如果您有更多,还需要添加其他一些退避或锁定机制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM