1

ビジネスケースを Cyclic Barriers の使用法にマッピングしようとしています。プロモーション オファーが進行中で、3 人の顧客のみがプロモーション オファーを取得できるとします。残りはオファーを受けません。

このシナリオをマッピングするために、Cyclic Barrier を利用しました。コードは機能していますが、一部の顧客がオファーを受けられないというシナリオをどのように処理すればよいかわかりません。今、タイムアウト値を指定して await() API を使用しようとしました。これにより、TimeoutExceptionをキャッチして、プロモーション オファーを利用できないことを顧客に知らせることができます。これにより、別の待機中のスレッドでBarrierBrokenExceptionが発生しました。

選択した顧客がプロモーション オファーを利用できる一方で、別のコード パスをたどることができなかった顧客など、これらのシナリオを適切に処理するにはどうすればよいか知りたいです。

私のコード -

public class CyclicBarrierExample {

 public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
    Thread[] threads = new Thread[5];
    CyclicBarrier barrier = new CyclicBarrier(3, ()->{System.out.println("Barrier limit of 3 reached. 3 threads will get the promotional offer!");});
    Runnable nr = new PromotionRunnable(barrier);

    int i = 0;
    for (Thread t : threads) {
        t = new Thread(nr, "Thread " + ++i);
        t.start();
    }
    System.out.println("main thread has completed");
 }

 private static class PromotionRunnable implements Runnable {
    private final CyclicBarrier barrier;

    public PromotionRunnable(final CyclicBarrier barrier) {
        this.barrier = barrier;
    }

    /*
     * As per the doc, BrokenBarrierException is thrown when another thread timed out while the current thread was waiting.
     * This explains why we are able to see both Timeout and Broken Barrier Exceptions.
     */
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " trying to get the promotional offer!");
        try {
            barrier.await(2000L, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
            return;
        } catch (BrokenBarrierException e) {
            System.out.println(Thread.currentThread().getName() + " could not get the promotional offer, due to barrier exception");
            return;
        } catch (TimeoutException e) {
            System.out.println(Thread.currentThread().getName() + " could not get the promotional offer, due to timeout exception");
            return;
        }
        System.out.println(Thread.currentThread().getName() + " got the promotional offer!");
    }
 }
}

実行の 1 つからの出力 -

  • スレッド 1 プロモーション オファーを取得しようとしています!
  • スレッド 4 プロモーション オファーを取得しようとしています!
  • メインスレッドが完了しました
  • スレッド 3 プロモーション オファーを取得しようとしています!
  • スレッド 2 プロモーション オファーを取得しようとしています!
  • スレッド 5 プロモーション オファーを取得しようとしています!
  • トップ 3 のバリアに到達しました。彼らはプロモーション オファーを受け取ります!
  • スレッド 2 はプロモーションオファーを受け取りました!
  • スレッド 1 がプロモーションのオファーを受け取りました!
  • スレッド 5 はプロモーションオファーを受け取りました!
  • タイムアウト例外のため、スレッド 3 はプロモーション オファーを取得できませんでした
  • バリア例外のため、スレッド 4 はプロモーション オファーを取得できませんでした
4

3 に答える 3

1

ACyclicBarrierは、3 人の顧客がオファーにアクセスしようとしている場合にのみ作動します。

したがって、1 人の顧客のみがアクセスしようとしている場合、他の 2 人の顧客もアクセスしようとするまでブロックされます! バリアがトリップすると、リセットされ、メカニズムが最初からやり直されます。5 つではなく 6 つ以上のスレッドを作成するかどうかを確認できます。

だからCyclicBarrierあなたが探しているものではないようです。

おそらく、オファーに既にアクセスした顧客の数を数えて、新しい顧客には拒否する必要があります。

private static class PromotionBarrier {
    private final AtomicBoolean hasAccess = new AtomicBoolean(false);
    private final AtomicLong counter = new AtomicLong(0);
    private final long maxCustomers = 3;
    public boolean hasAccess() {
        if(hasAccess.get()) {
            long value = counter.incrementAndGet();
            if(value <= maxCustomers) {
                return true;
            } else {
                hasAccess.set(false);
                return false;
            }
        }
        return false; 
    }
}

private static class PromotionRunnable implements Runnable {
    private final PromotionBarrier promotionBarrier;

    public PromotionRunnable(final PromotionBarrier promotionBarrier) {
        this.promotionBarrier = barrier;
    }

    @Override
    public void run() {
        if(promotionBarrier.hasAccess()) {
            // Yoohoo I got it!
        } else {
            // Rha I am too late!!
        }
    }
于 2015-08-27T14:25:27.170 に答える
0

CyclicBarrier複数のスレッドがあり、それらすべてが同時に何かを開始するようにしたい場合に使用します。バリアが N スレッドに設定されている場合、最初の N-1 スレッドは N 番目のスレッドが到着するまで待機し、その後、すべてのスレッドが再び実行されます。

それはおそらくあなたが望むものではありません。最初の 3 つのスレッドで賞を獲得し、残りのスレッドは手ぶらで去っていきます。 スレッドに何かを待機CyclicBarrierさせることがすべてですが、スレッドに待機させたいものは何もありません。

Semaphoreまた、スレッドに何かを待機させることもすべてです。

AtomicInteger の使用に関する @OldCurmudgeon の提案が気に入っています。

賞品の数に等しい を設定し、AtomicInteger各スレッドに を呼び出しますai.decrementAndGet()。結果が >= 0 の場合、スレッドは賞を獲得できます。結果が 0 未満の場合は、申し訳ありませんが賞品はありません。

于 2015-08-27T14:31:19.463 に答える