package org.dcache.util; import com.google.common.annotations.VisibleForTesting; import java.util.Date; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Atomic counter that supports waiting for the counter to change. */ public class AtomicCounter { private final Lock _lock = new ReentrantLock(); private final Condition _updated = _lock.newCondition(); private int _counter; /** * Increment the counter by one. */ public void increment() { _lock.lock(); try { inLock(); _counter++; _updated.signalAll(); } finally { _lock.unlock(); } } /** * Increment the current value of the counter. */ public int get() { _lock.lock(); try { inLock(); return _counter; } finally { _lock.unlock(); } } /** * Waits for the counter to change to a value different from * <code>value</code>. * * The method returns when one of the following happens: * * * The current counter value is different from the * <code>value</code> argument; or * * * Some other thread invokes the <code>increment</code> method for * this AtomicCounter; or * * * Some other thread interrupts the current thread; or * * * The specified deadline elapses; or * * * A "spurious wakeup" occurs. * * @param value the value to wait for the counter to change away from * @param deadline the absolute time to wait until * @return true if the counter has a different value than {@code value} upon return * @throw InterruptedException if the current thread is interrupted */ public boolean awaitChangeUntil(int value, Date deadline) throws InterruptedException { _lock.lock(); try { inLock(); return _counter != value || _updated.awaitUntil(deadline); } finally { _lock.unlock(); } } @VisibleForTesting void inLock() { } }