Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 处理与循环障碍相关的异常的更好方法_Java_Multithreading_Concurrency_Java.util.concurrent_Cyclicbarrier - Fatal编程技术网

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

Java 处理与循环障碍相关的异常的更好方法,java,multithreading,concurrency,java.util.concurrent,cyclicbarrier,Java,Multithreading,Concurrency,Java.util.concurrent,Cyclicbarrier,我试图将一些商业案例映射到循环屏障的使用上。假设我们正在进行促销活动,只有3位客户可以获得促销活动。其余的人将得不到报价 为了映射这个场景,我使用了循环屏障。即使代码正在运行,我也不确定如何处理一些客户无法获得报价的情况。现在,我尝试使用带有超时值的wait()API,以便捕获TimeoutException,并让客户知道他无法获得促销优惠。这导致另一个等待线程出现异常 我想知道,我们如何才能优雅地处理这些场景,使选定的客户获得促销优惠,而那些无法遵循不同代码路径的客户 我的代码- public

我试图将一些商业案例映射到循环屏障的使用上。假设我们正在进行促销活动,只有3位客户可以获得促销活动。其余的人将得不到报价

为了映射这个场景,我使用了循环屏障。即使代码正在运行,我也不确定如何处理一些客户无法获得报价的情况。现在,我尝试使用带有超时值的wait()API,以便捕获TimeoutException,并让客户知道他无法获得促销优惠。这导致另一个等待线程出现异常

我想知道,我们如何才能优雅地处理这些场景,使选定的客户获得促销优惠,而那些无法遵循不同代码路径的客户

我的代码-

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试图获得促销优惠
  • 达到前三名的门槛,他们将获得促销优惠
  • 线程2得到了促销优惠
  • 线程1得到了促销优惠
  • 线程5得到了促销优惠
  • 由于超时异常,线程3无法获得促销优惠
  • 由于障碍例外,线程4无法获得促销优惠
您正在错误地使用。这是为了让多个线程同步

一种同步辅助工具,允许一组线程都等待对方到达一个共同的障碍点。CyclicBarrier在涉及固定大小的线程组的程序中很有用,这些线程有时必须互相等待。该屏障被称为循环屏障,因为它可以在释放等待的线程后重新使用

虽然我不确定你需要什么,但你可能需要使用一个

计数信号灯。从概念上讲,信号量维护一组许可。如果需要,每个acquire()都会阻塞,直到有许可证可用,然后再获取它。每次释放()都会添加一个许可证,可能会释放阻止收单机构。但是,没有使用实际的许可证对象;信号量只保留可用数量的计数,并相应地进行操作

你可能在找一个新的工作

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


只有当3名客户试图访问此优惠时,
CyclicBarrier
才会跳闸

因此,如果只有一个客户尝试访问它,它将阻止,直到另外两个客户也尝试访问它!一旦障碍物跳闸,它就被简单地重置,麦加主义就重新开始了。您可以观察是否创建了6个以上的线程,而不是5个

因此,
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!!
        }
    }
私有静态类升级屏障{
private final AtomicBoolean hasAccess=新的AtomicBoolean(false);
专用最终AtomicLong计数器=新的AtomicLong(0);
私人最终最大长客户数=3;
公共访问权限(){
if(hasAccess.get()){
long value=counter.incrementAndGet();

如果(value
CyclicBarrier
用于当您有多个线程时,并且您希望它们同时开始执行某些操作。如果为N个线程设置了屏障,则它会使前N-1个线程等待第N个线程到达,然后让它们再次执行

这可能不是您想要的。您希望前3个线程获得奖品,其余线程空手而归。
CyclicBarrier
就是让线程等待一些东西,但您不希望线程等待任何东西

Semaphore
也就是让线程等待一些东西

我喜欢@OldCurmudgeon关于使用原子整数的建议


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

是的,在阅读完评论后,CyclicBarrier可能不是用于我假设场景的正确构造。你能告诉我使用循环屏障的实际场景吗?我也在考虑bout用计数信号量实现了同样的功能,但不确定用例对信号量是否有效。@user3842182 CyclicBarrier在涉及固定大小的线程组的程序中很有用,这些线程组有时必须相互等待。-不能说更多了。