java并发:轻量级非阻塞信号量?
我遇到一种情况,我想执行一次回调。为了便于论证,我们假设它看起来像这样:
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 个使用许可,则使用其中一个并返回 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() 方法 没有返回值,并且不能使用 getCount() 以原子方式执行。
我应该只使用 Semaphore 还是有更合适的类?
I have a situation where I have a callback that I want to execute once. For the sake of argument let's say it looks like this:
final X once = new X(1);
Runnable r = new Runnable() {
@Override public void run() {
if (once.use())
doSomething();
}
}
where X is some concurrent object with the following behavior:
constructor: X(int N) -- allocates N use permits
boolean use()
: If there is at least 1 use permit, consume one of them and return true. Otherwise return false. This operation is atomic with respect to multiple threads.
I know I can use java.util.concurrent.Semaphore for this, but I don't need the blocking/waiting aspect of it, and I want this to be a one-time use thing.
AtomicInteger doesn't look sufficient unless I do something like
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;
}
}
and I feel queasy about the while loop.
CountDownLatch won't work, because the countDown() method has no return value and can't be executed atomically w/r/t getCount().
Should I just use Semaphore or is there a more appropriate class?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在单个许可的情况下,您可以使用
AtomicBoolean
:如果您需要多个许可,请使用
compareAndSet()
解决方案。不用担心循环,getAndIncrement()
在幕后的工作方式相同。In the case of single permit you can use
AtomicBoolean
:If you need many permits, use your solution with
compareAndSet()
. Don't worry about the loop,getAndIncrement()
works the same way under the cover.是的。 AtomicInteger 是非阻塞的。您可以使用 getAndDecrement()。
您可以使用类似的方法,
只要您在递减和集合之间不调用它二十亿次,这就会起作用。也就是说,您需要有 20 亿个线程在这两个语句之间停止。
同样,您可以使用 AtomicLong 来进行额外的偏执。
yes. AtomicInteger is non-blocking. You can use getAndDecrement().
You can use something like
This will work provided you don't call it two billion times between the decrement and the set. i.e. you would need to have two billion threads stop between these two statements.
Again you can use AtomicLong for extra paranoia.
如果您发现非法获得许可,则将计数器设置回零,从而在另一个线程释放许可时产生竞争条件。这只适用于最多 2 或 3 个线程的情况。如果您有更多,则需要添加一些其他退避或锁定机制。
Setting the counter back to zero if you discover the permit was illegally obtained creates a race condition when another thread releases a permit. This only works for situations where there are 2 or 3 threads at most. Some other backoff or latching mechanism needs to be added if you have more.