首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >处理与循环障碍相关的异常的更好方法

处理与循环障碍相关的异常的更好方法
EN

Stack Overflow用户
提问于 2015-08-27 14:00:52
回答 3查看 310关注 0票数 1

我试图将一些商业案例映射到循环壁垒的使用上。假设我们有一个促销优惠正在进行,只有3个客户可以得到促销优惠。其余的人都不会得到这个提议。

为了映射这个场景,我使用了循环屏障。即使代码工作正常,我也不知道如何处理一些客户无法获得报价的场景。现在,我尝试使用具有超时值的await() API,这样我就可以捕获TimeoutException并让客户知道他无法利用促销服务。这导致了另一个等待线程的BarrierBrokenException

我想知道,我们如何优雅地处理这些场景,以便选定的客户可以利用促销优惠,而那些谁不能遵循不同的代码路径。

我的密码-

代码语言:javascript
运行
复制
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试图得到的促销优惠!
  • 线4试图得到促销优惠!
  • 主线程已经完成
  • 线程3试图得到促销优惠!
  • 线2试图得到促销优惠!
  • 线5试图得到的促销优惠!
  • 障碍达到前3名,他们将得到促销优惠!
  • 线2得到了促销优惠!
  • 线1得到了促销优惠!
  • 线5得到了促销优惠!
  • 由于超时异常,线程3无法获得促销优惠。
  • 由于障碍例外,线程4无法获得促销优惠。
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-08-27 14:25:27

只有当3个客户试图访问该报价时,CyclicBarrier才会绊倒。

因此,如果只有一个客户试图访问它,它将阻塞,直到其他两个客户试图访问它!一旦障碍发生,它就会被重置,而机械主义就会重新开始。您可以观察是否创建6+线程而不是5。

因此,CyclicBarrier似乎不是您要找的东西。

您可能想数一下已经访问了该报价并拒绝给新客户的客户数量:

代码语言:javascript
运行
复制
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!!
        }
    }
票数 1
EN

Stack Overflow用户

发布于 2015-08-27 14:17:44

您使用的CyclicBarrier不正确。它是由许多线程同步的。

一种同步工具,它允许一组线程都等待对方到达一个共同的障碍点。CyclicBarriers在涉及固定大小线程的程序中非常有用,这些线程必须偶尔等待对方。这个屏障被称为循环,因为它可以在等待线程释放后被重用。

您可能需要使用信号量,尽管我不确定您需要什么。

计数信号量。从概念上讲,信号量维护着一组许可证。如果有必要,每个人都会阻塞,直到获得许可证,然后才能获得许可。每个版本()都会添加一个许可,可能会释放一个阻塞获取者。但是,没有使用实际的许可证对象;信号量只对可用的数字进行计数,并相应地执行操作。

你可能在找一个AtomicInteger

一个可以原子更新的int值。有关原子变量属性的描述,请参阅java.util.concurrent.atomic包规范。AtomicInteger在诸如原子递增计数器等应用程序中使用,不能用作整数的替换。

票数 0
EN

Stack Overflow用户

发布于 2015-08-27 14:31:19

CyclicBarrier用于当您有几个线程时,您希望它们都同时开始执行一些事情。如果为N个线程设置了屏障,那么它会让第一个N1线程等待N‘the线程到达,然后再让它们全部运行。

这可能不是你想要的。你想要前三个线程索要奖品,其余的则空手离去。CyclicBarrier主要是让线程等待一些东西,但是没有什么需要线程等待的。

Semaphore也是让线程等待一些东西的全部。

我喜欢@OldCurmudgeon版关于使用AtomicInteger的建议。

设置一个等于奖品数量的AtomicInteger,然后让每个线程调用ai.decrementAndGet()。如果结果是>= 0,则线程可以申请奖励。如果结果是< 0,那么很抱歉,但没有奖品。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32251462

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档