3

一度実行したいコールバックがある状況があります。議論のために、次のように見えるとしましょう。

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 つでもある場合、そのうちの 1 つを消費して true を返します。それ以外の場合は false を返します。この操作は、複数のスレッドに関してアトミックです。

これにはjava.util.concurrent.Semaphoreを使用できることはわかっていますが、ブロッキング/待機の側面は必要ないため、これを 1 回限りの使用にしたいと考えています。

私が何かをしない限り、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 ループにうんざりします。

countDown() メソッドには戻り値がなく、getCount() を使用してアトミックに実行できないため、CountDownLatch は機能しません。

セマフォを使用するだけですか、それともより適切なクラスがありますか?

4

3 に答える 3

4

単一の許可証の場合、あなたは使用することができますAtomicBoolean

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

多くの許可が必要な場合は、でソリューションを使用してくださいcompareAndSet()。ループについて心配する必要はありませんgetAndIncrement()。カバーの下でも同じように機能します。

于 2011-03-22T17:25:37.923 に答える
1

はい。AtomicInteger はノンブロッキングです。getAndDecrement() を使用できます。

次のようなものを使用できます

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

デクリメントとセットの間で 20 億回呼び出さない限り、これは機能します。つまり、これら 2 つのステートメントの間で 20 億のスレッドを停止する必要があります。

ここでも、AtomicLong を追加のパラノイアに使用できます。

于 2011-03-22T17:18:15.713 に答える
0
// 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 つのスレッドがある状況でのみ機能します。他のバックオフまたはラッチ メカニズムを追加する必要がある場合は、追加する必要があります。

于 2016-07-13T12:43:05.497 に答える