[英]java concurrency: lightweight nonblocking semaphore?
我有一个情况,我有一个我想要执行一次的回调。 为了论证,让我们说它看起来像这样:
final X once = new X(1);
Runnable r = new Runnable() {
@Override public void run() {
if (once.use())
doSomething();
}
}
其中X是一些具有以下行为的并发对象:
构造函数:X(int N) - 分配N个使用许可
boolean use()
:如果至少有1个use permit,则使用其中一个并返回true。 否则返回false。 该操作对于多个线程是原子的。
我知道我可以使用java.util.concurrent.Semaphore ,但我不需要它的阻塞/等待方面,我希望这是一次性使用的东西。
除非我做类似的事情,否则AtomicInteger看起来不够
class NTimeUse {
final private AtomicInteger count;
public NTimeUse(int N) { this.count = new AtomicInteger(N); }
public boolean use() {
while (true)
{
int n = this.count.get();
if (n == 0)
return false;
if (this.count.compareAndSet(n, n-1))
return true;
}
}
而我对while循环感到不安。
CountDownLatch将不起作用,因为countDown()方法没有返回值,并且不能以原子方式执行w / r / t getCount()。
我应该只使用信号量还是有更合适的类?
在单一许可的情况下,您可以使用AtomicBoolean
:
final AtomicBoolean once = new AtomicBoolean(true);
Runnable r = new Runnable() {
@Override public void run() {
if (once.getAndSet(false))
doSomething();
}
}
如果您需要许多许可,请使用compareAndSet()
解决方案。 不要担心循环, getAndIncrement()
在封面下的工作方式相同。
是。 AtomicInteger是非阻塞的。 您可以使用getAndDecrement()。
你可以使用类似的东西
if(counter.getAndDecrement() > 0) {
// something
} else {
counter.set(0);
}
如果你在减量和集合之间没有调用它20亿次,这将有效。 即你需要在这两个语句之间停止20亿个线程。
你可以再次使用AtomicLong来获得额外的偏执狂。
// This implements an unfair locking scheme:
while ( mayContinue() ) {
// acquire the permit and check if it was legally obtained
if ( counter.decrementAndGet() > 0 )
return true;
// return the illegally acquired permit
counter.incrementAndGet();
}
return false;
如果您发现非法获得许可证,则将计数器设置回零会在另一个线程释放许可证时创建竞争条件。 这仅适用于最多有2个或3个线程的情况。 如果您有更多,还需要添加其他一些退避或锁定机制。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.