/** * Instantiates a CounterLatch object with an initial value and a wait value. * @param initial - initial value of the counter * @param waitValue - when the counter holds this value, * threads calling {@link #await()} or {@link #await(long, TimeUnit)} * will wait until the counter changes value or until they are interrupted. */ public CounterLatch(long initial, long waitValue) { this.signal = waitValue; this.count = new AtomicLong(initial); this.sync = new Sync(); }
/** * Performs an atomic update of the counter * If the operation is successful and {@code expect==waitValue && expect!=update} waiting threads will be released. * @param expect - the expected counter value * @param update - the new counter value * @return <code>true</code> if successful, <code>false</code> if the * current value wasn't as expected */ public boolean compareAndSet(long expect, long update) { boolean result = count.compareAndSet(expect, update); if (result && expect==signal && expect != update) { sync.releaseShared(0); } return result; }
/** * Causes the calling thread to wait if the counter holds the waitValue. * If the counter holds any other value, the thread will return * If the thread is interrupted or becomes interrupted an InterruptedException is thrown * @return true if the value changed, false if the timeout has elapsed * @throws InterruptedException */ public boolean await(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); }
/** * Decrements the counter * @return the previous counter value */ public long countDown() { long previous = count.getAndDecrement(); if (previous == signal) { sync.releaseShared(0); } return previous; }
/** * Increments the counter * @return the previous counter value */ public long countUp() { long previous = count.getAndIncrement(); if (previous == signal) { sync.releaseShared(0); } return previous; }
/** * Returns a collection of the blocked threads * @return a collection of the blocked threads */ public Collection<Thread> getQueuedThreads() { return sync.getQueuedThreads(); }
/** * releases all waiting threads. This operation is permanent, and no threads will block, * even if the counter hits the {@code waitValue} until {@link #reset(long)} has been called. * @return <code>true</code> if this release of shared mode may permit a * waiting acquire (shared or exclusive) to succeed; and * <code>false</code> otherwise */ public boolean releaseAll() { released = true; return sync.releaseShared(0); }
/** * Causes the calling thread to wait if the counter holds the waitValue. * If the counter holds any other value, the thread will return * If the thread is interrupted or becomes interrupted an InterruptedException is thrown * @throws InterruptedException */ public void await() throws InterruptedException { sync.acquireSharedInterruptibly(1); }
/** * returns true if there are threads blocked by this latch * @return true if there are threads blocked by this latch */ public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }