TimeoutScheduler { public CompletableFuture<Void> whenTimingOut() { final TimeoutFuture whenTimingOut = this.whenTimingOut; if (whenTimingOut != null) { return whenTimingOut; } final TimeoutFuture timeoutFuture = new TimeoutFuture(); if (whenTimingOutUpdater.compareAndSet(this, null, timeoutFuture)) { return timeoutFuture; } else { return this.whenTimingOut; } } TimeoutScheduler(long timeoutNanos); void init(EventExecutor eventLoop, TimeoutTask timeoutTask, long initialTimeoutNanos); void clearTimeout(); void clearTimeout(boolean resetTimeout); void setTimeoutNanos(TimeoutMode mode, long timeoutNanos); void timeoutNow(); boolean isTimedOut(); long timeoutNanos(); CompletableFuture<Void> whenTimingOut(); CompletableFuture<Void> whenTimedOut(); @Nullable Long startTimeNanos();  }
@Test void whenTimingOut() { final AtomicReference<CompletableFuture<Void>> timeoutFutureRef = new AtomicReference<>(); final AtomicReference<TimeoutScheduler> timeoutSchedulerRef = new AtomicReference<>(); final AtomicBoolean completed = new AtomicBoolean(); final AtomicBoolean passed = new AtomicBoolean(); eventExecutor.execute(() -> { final TimeoutScheduler timeoutScheduler = new TimeoutScheduler(0); final TimeoutTask timeoutTask = new TimeoutTask() { @Override public boolean canSchedule() { return true; } @Override public void run() { assertThat(timeoutScheduler.whenTimingOut()).isDone(); assertThat(timeoutScheduler.isTimedOut()).isTrue(); assertThat(timeoutScheduler.whenTimedOut()).isNotDone(); passed.set(true); } }; timeoutScheduler.init(eventExecutor, timeoutTask, 0); assertThat(timeoutScheduler.isTimedOut()).isFalse(); timeoutScheduler.setTimeoutNanos(SET_FROM_NOW, MILLISECONDS.toNanos(1000)); assertThat(timeoutScheduler.state()).isEqualTo(State.SCHEDULED); timeoutSchedulerRef.set(timeoutScheduler); timeoutFutureRef.set(timeoutScheduler.whenTimedOut()); completed.set(true); }); await().untilTrue(passed); await().untilTrue(completed); timeoutFutureRef.get().join(); assertThat(timeoutSchedulerRef.get().state()).isEqualTo(State.TIMED_OUT); }