Thanks Tim, I had forgotten that the ICountDownLatch is reusable, unlike CountDownLatch.
What I ended up doing, however, was doing an additional check before acquiring the lock.
Instead of this:
if( semaphore.tryAcquire() ) {
// do stuff
}
I now go
if( semaphore.availablePermits() != 0 && semaphore.tryAcquire() ) {
// do stuff
}
which avoids the call to tryAcquire if there are no permits available. This is lame, but seems to work for my needs.
I'd still like to know when the ISemaphore behavior got fixed, however.