Java 处理与循环障碍相关的异常的更好方法
我试图将一些商业案例映射到循环屏障的使用上。假设我们正在进行促销活动,只有3位客户可以获得促销活动。其余的人将得不到报价 为了映射这个场景,我使用了循环屏障。即使代码正在运行,我也不确定如何处理一些客户无法获得报价的情况。现在,我尝试使用带有超时值的wait()API,以便捕获TimeoutException,并让客户知道他无法获得促销优惠。这导致另一个等待线程出现异常 我想知道,我们如何才能优雅地处理这些场景,使选定的客户获得促销优惠,而那些无法遵循不同代码路径的客户 我的代码-Java 处理与循环障碍相关的异常的更好方法,java,multithreading,concurrency,java.util.concurrent,cyclicbarrier,Java,Multithreading,Concurrency,Java.util.concurrent,Cyclicbarrier,我试图将一些商业案例映射到循环屏障的使用上。假设我们正在进行促销活动,只有3位客户可以获得促销活动。其余的人将得不到报价 为了映射这个场景,我使用了循环屏障。即使代码正在运行,我也不确定如何处理一些客户无法获得报价的情况。现在,我尝试使用带有超时值的wait()API,以便捕获TimeoutException,并让客户知道他无法获得促销优惠。这导致另一个等待线程出现异常 我想知道,我们如何才能优雅地处理这些场景,使选定的客户获得促销优惠,而那些无法遵循不同代码路径的客户 我的代码- public
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无法获得促销优惠
只有当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();
如果(valueCyclicBarrier
用于当您有多个线程时,并且您希望它们同时开始执行某些操作。如果为N个线程设置了屏障,则它会使前N-1个线程等待第N个线程到达,然后让它们再次执行
这可能不是您想要的。您希望前3个线程获得奖品,其余线程空手而归。CyclicBarrier
就是让线程等待一些东西,但您不希望线程等待任何东西
Semaphore
也就是让线程等待一些东西
我喜欢@OldCurmudgeon关于使用原子整数的建议
设置一个等于奖品数量的AtomicInteger
,然后让每个线程调用ai.decrementAndGet()
。如果结果>=0,线程可以申请奖品。如果结果<0,那么很抱歉,但是没有奖品。是的,在阅读完评论后,CyclicBarrier可能不是用于我假设场景的正确构造。你能告诉我使用循环屏障的实际场景吗?我也在考虑bout用计数信号量实现了同样的功能,但不确定用例对信号量是否有效。@user3842182 CyclicBarrier在涉及固定大小的线程组的程序中很有用,这些线程组有时必须相互等待。-不能说更多了。