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?
In the case of single permit you can use AtomicBoolean
:
final AtomicBoolean once = new AtomicBoolean(true);
Runnable r = new Runnable() {
@Override public void run() {
if (once.getAndSet(false))
doSomething();
}
}
If you need many permits, use your solution with compareAndSet()
. Don't worry about the loop, getAndIncrement()
works the same way under the cover.