/** * Gets a future that completes when the state is no longer {@code .equals()} to {@code currentState)}. */ public CompletableFuture<T> getStateChange(T currentState) { checkState(!Thread.holdsLock(lock), "Can not wait for state change while holding the lock"); requireNonNull(currentState, "currentState is null"); synchronized (lock) { // return a completed future if the state has already changed, or we are in a terminal state if (isPossibleStateChange(currentState)) { return CompletableFuture.completedFuture(state); } return futureStateChange.get().createNewListener(); } }
/** * Wait for the state to not be {@code .equals()} to the specified current state. */ public Duration waitForStateChange(T currentState, Duration maxWait) throws InterruptedException { checkState(!Thread.holdsLock(lock), "Can not wait for state change while holding the lock"); requireNonNull(currentState, "currentState is null"); requireNonNull(maxWait, "maxWait is null"); // don't wait if the state has already changed, or we are in a terminal state if (isPossibleStateChange(currentState)) { return maxWait; } // wait for task state to change long remainingNanos = maxWait.roundTo(NANOSECONDS); long start = System.nanoTime(); long end = start + remainingNanos; synchronized (lock) { while (remainingNanos > 0 && !isPossibleStateChange(currentState)) { // wait for timeout or notification NANOSECONDS.timedWait(lock, remainingNanos); remainingNanos = end - System.nanoTime(); } } if (remainingNanos < 0) { remainingNanos = 0; } return new Duration(remainingNanos, NANOSECONDS); }