All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.atomix.utils.concurrent.OrderedFuture Maven / Gradle / Ivy

There is a newer version: 8.7.0-alpha1
Show newest version
/*
 * Copyright 2017-present Open Networking Foundation
 * Copyright © 2020 camunda services GmbH ([email protected])
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.atomix.utils.concurrent;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * A {@link CompletableFuture} that ensures callbacks are called in FIFO order.
 *
 * 

The default {@link CompletableFuture} does not guarantee the ordering of callbacks, and indeed * appears to execute them in LIFO order. */ public class OrderedFuture extends CompletableFuture { private final Queue> orderedFutures = new LinkedList<>(); private volatile boolean complete; private volatile T result; private volatile Throwable error; public OrderedFuture() { super.whenComplete(this::complete); } /** * Wraps the given future in a new blockable future. * * @param future the future to wrap * @param the future value type * @return a new blockable future */ public static CompletableFuture wrap(final CompletableFuture future) { final CompletableFuture newFuture = new OrderedFuture<>(); future.whenComplete( (result, error) -> { if (error == null) { newFuture.complete(result); } else { newFuture.completeExceptionally(error); } }); return newFuture; } @Override public CompletableFuture thenApply(final Function fn) { return wrap(orderedFuture().thenApply(fn)); } @Override public CompletableFuture thenApplyAsync(final Function fn) { return wrap(orderedFuture().thenApplyAsync(fn)); } @Override public CompletableFuture thenApplyAsync( final Function fn, final Executor executor) { return wrap(orderedFuture().thenApplyAsync(fn, executor)); } @Override public CompletableFuture thenAccept(final Consumer action) { return wrap(orderedFuture().thenAccept(action)); } @Override public CompletableFuture thenAcceptAsync(final Consumer action) { return wrap(orderedFuture().thenAcceptAsync(action)); } @Override public CompletableFuture thenAcceptAsync( final Consumer action, final Executor executor) { return wrap(orderedFuture().thenAcceptAsync(action, executor)); } @Override public CompletableFuture thenRun(final Runnable action) { return wrap(orderedFuture().thenRun(action)); } @Override public CompletableFuture thenRunAsync(final Runnable action) { return wrap(orderedFuture().thenRunAsync(action)); } @Override public CompletableFuture thenRunAsync(final Runnable action, final Executor executor) { return wrap(orderedFuture().thenRunAsync(action, executor)); } @Override public CompletableFuture thenCombine( final CompletionStage other, final BiFunction fn) { return wrap(orderedFuture().thenCombine(other, fn)); } @Override public CompletableFuture thenCombineAsync( final CompletionStage other, final BiFunction fn) { return wrap(orderedFuture().thenCombineAsync(other, fn)); } @Override public CompletableFuture thenCombineAsync( final CompletionStage other, final BiFunction fn, final Executor executor) { return wrap(orderedFuture().thenCombineAsync(other, fn, executor)); } @Override public CompletableFuture thenAcceptBoth( final CompletionStage other, final BiConsumer action) { return wrap(orderedFuture().thenAcceptBoth(other, action)); } @Override public CompletableFuture thenAcceptBothAsync( final CompletionStage other, final BiConsumer action) { return wrap(orderedFuture().thenAcceptBothAsync(other, action)); } @Override public CompletableFuture thenAcceptBothAsync( final CompletionStage other, final BiConsumer action, final Executor executor) { return wrap(orderedFuture().thenAcceptBothAsync(other, action, executor)); } @Override public CompletableFuture runAfterBoth( final CompletionStage other, final Runnable action) { return wrap(orderedFuture().runAfterBoth(other, action)); } @Override public CompletableFuture runAfterBothAsync( final CompletionStage other, final Runnable action) { return wrap(orderedFuture().runAfterBothAsync(other, action)); } @Override public CompletableFuture runAfterBothAsync( final CompletionStage other, final Runnable action, final Executor executor) { return wrap(orderedFuture().runAfterBothAsync(other, action, executor)); } @Override public CompletableFuture applyToEither( final CompletionStage other, final Function fn) { return wrap(orderedFuture().applyToEither(other, fn)); } @Override public CompletableFuture applyToEitherAsync( final CompletionStage other, final Function fn) { return wrap(orderedFuture().applyToEitherAsync(other, fn)); } @Override public CompletableFuture applyToEitherAsync( final CompletionStage other, final Function fn, final Executor executor) { return wrap(orderedFuture().applyToEitherAsync(other, fn, executor)); } @Override public CompletableFuture acceptEither( final CompletionStage other, final Consumer action) { return wrap(orderedFuture().acceptEither(other, action)); } @Override public CompletableFuture acceptEitherAsync( final CompletionStage other, final Consumer action) { return wrap(orderedFuture().acceptEitherAsync(other, action)); } @Override public CompletableFuture acceptEitherAsync( final CompletionStage other, final Consumer action, final Executor executor) { return wrap(orderedFuture().acceptEitherAsync(other, action, executor)); } @Override public CompletableFuture runAfterEither( final CompletionStage other, final Runnable action) { return wrap(orderedFuture().runAfterEither(other, action)); } @Override public CompletableFuture runAfterEitherAsync( final CompletionStage other, final Runnable action) { return wrap(orderedFuture().runAfterEitherAsync(other, action)); } @Override public CompletableFuture runAfterEitherAsync( final CompletionStage other, final Runnable action, final Executor executor) { return wrap(orderedFuture().runAfterEitherAsync(other, action, executor)); } @Override public CompletableFuture thenCompose( final Function> fn) { return wrap(orderedFuture().thenCompose(fn)); } @Override public CompletableFuture thenComposeAsync( final Function> fn) { return wrap(orderedFuture().thenComposeAsync(fn)); } @Override public CompletableFuture thenComposeAsync( final Function> fn, final Executor executor) { return wrap(orderedFuture().thenComposeAsync(fn, executor)); } @Override public CompletableFuture whenComplete(final BiConsumer action) { return wrap(orderedFuture().whenComplete(action)); } @Override public CompletableFuture whenCompleteAsync( final BiConsumer action) { return wrap(orderedFuture().whenCompleteAsync(action)); } @Override public CompletableFuture whenCompleteAsync( final BiConsumer action, final Executor executor) { return wrap(orderedFuture().whenCompleteAsync(action, executor)); } @Override public CompletableFuture handle(final BiFunction fn) { return wrap(orderedFuture().handle(fn)); } @Override public CompletableFuture handleAsync( final BiFunction fn) { return wrap(orderedFuture().handleAsync(fn)); } @Override public CompletableFuture handleAsync( final BiFunction fn, final Executor executor) { return wrap(orderedFuture().handleAsync(fn, executor)); } @Override public CompletableFuture toCompletableFuture() { return this; } @Override public CompletableFuture exceptionally(final Function fn) { return wrap(orderedFuture().exceptionally(fn)); } /** Adds a new ordered future. */ private CompletableFuture orderedFuture() { if (!complete) { synchronized (orderedFutures) { if (!complete) { final CompletableFuture future = new CompletableFuture<>(); orderedFutures.add(future); return future; } } } // Completed if (error == null) { return CompletableFuture.completedFuture(result); } else { return failedFuture(error); } } /** Completes futures in FIFO order. */ private void complete(final T result, final Throwable error) { synchronized (orderedFutures) { this.result = result; this.error = error; complete = true; if (error == null) { for (final CompletableFuture future : orderedFutures) { future.complete(result); } } else { for (final CompletableFuture future : orderedFutures) { future.completeExceptionally(error); } } orderedFutures.clear(); } } }