我试图将一些商业案例映射到循环壁垒的使用上。假设我们有一个促销优惠正在进行,只有3个客户可以得到促销优惠。其余的人都不会得到这个提议。
为了映射这个场景,我使用了循环屏障。即使代码工作正常,我也不知道如何处理一些客户无法获得报价的场景。现在,我尝试使用具有超时值的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!");
}
}
}
其中一次的输出-
发布于 2015-08-27 14:25:27
只有当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!!
}
}
发布于 2015-08-27 14:17:44
您使用的CyclicBarrier不正确。它是由许多线程同步的。
一种同步工具,它允许一组线程都等待对方到达一个共同的障碍点。CyclicBarriers在涉及固定大小线程的程序中非常有用,这些线程必须偶尔等待对方。这个屏障被称为循环,因为它可以在等待线程释放后被重用。
您可能需要使用信号量,尽管我不确定您需要什么。
计数信号量。从概念上讲,信号量维护着一组许可证。如果有必要,每个人都会阻塞,直到获得许可证,然后才能获得许可。每个版本()都会添加一个许可,可能会释放一个阻塞获取者。但是,没有使用实际的许可证对象;信号量只对可用的数字进行计数,并相应地执行操作。
你可能在找一个AtomicInteger。
一个可以原子更新的int值。有关原子变量属性的描述,请参阅java.util.concurrent.atomic包规范。AtomicInteger在诸如原子递增计数器等应用程序中使用,不能用作整数的替换。
发布于 2015-08-27 14:31:19
CyclicBarrier
用于当您有几个线程时,您希望它们都同时开始执行一些事情。如果为N个线程设置了屏障,那么它会让第一个N1线程等待N‘the线程到达,然后再让它们全部运行。
这可能不是你想要的。你想要前三个线程索要奖品,其余的则空手离去。CyclicBarrier
主要是让线程等待一些东西,但是没有什么需要线程等待的。
Semaphore
也是让线程等待一些东西的全部。
我喜欢@OldCurmudgeon版关于使用AtomicInteger的建议。
设置一个等于奖品数量的AtomicInteger
,然后让每个线程调用ai.decrementAndGet()
。如果结果是>= 0,则线程可以申请奖励。如果结果是< 0,那么很抱歉,但没有奖品。
https://stackoverflow.com/questions/32251462
复制相似问题