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

com.pivovarit.collectors.Dispatcher Maven / Gradle / Ivy

package com.pivovarit.collectors;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.Semaphore;
import java.util.function.BiConsumer;
import java.util.function.Supplier;

/**
 * @author Grzegorz Piwowarek
 */
final class Dispatcher {

    private final CompletableFuture completionSignaller = new CompletableFuture<>();
    private final Executor executor;
    private final Semaphore limiter;

    private Dispatcher() {
        this.executor = Executors.newVirtualThreadPerTaskExecutor();
        this.limiter = null;
    }

    private Dispatcher(Executor executor, int permits) {
        this.executor = executor;
        this.limiter = new Semaphore(permits);
    }

    static  Dispatcher from(Executor executor, int permits) {
        return new Dispatcher<>(executor, permits);
    }

    static  Dispatcher virtual() {
        return new Dispatcher<>();
    }

    CompletableFuture enqueue(Supplier supplier) {
        InterruptibleCompletableFuture future = new InterruptibleCompletableFuture<>();
        completionSignaller.whenComplete(shortcircuit(future));
        try {
            executor.execute(completionTask(supplier, future));
        } catch (Throwable e) {
            completionSignaller.completeExceptionally(e);
            return CompletableFuture.failedFuture(e);
        }
        return future;
    }

    private FutureTask completionTask(Supplier supplier, InterruptibleCompletableFuture future) {
        FutureTask task = new FutureTask<>(() -> {
            if (!completionSignaller.isCompletedExceptionally()) {
                try {
                    if (limiter == null) {
                        future.complete(supplier.get());
                    } else {
                        try {
                            limiter.acquire();
                            future.complete(supplier.get());
                        } finally {
                            limiter.release();
                        }
                    }
                } catch (Throwable e) {
                    completionSignaller.completeExceptionally(e);
                }
            }
        }, null);
        future.completedBy(task);
        return task;
    }

    private static  BiConsumer shortcircuit(InterruptibleCompletableFuture future) {
        return (__, throwable) -> {
            if (throwable != null) {
                future.completeExceptionally(throwable);
                future.cancel(true);
            }
        };
    }

    static final class InterruptibleCompletableFuture extends CompletableFuture {

        private volatile FutureTask backingTask;

        private void completedBy(FutureTask task) {
            backingTask = task;
        }

        @Override
        public boolean cancel(boolean mayInterruptIfRunning) {
            var task = backingTask;
            if (task != null) {
                task.cancel(mayInterruptIfRunning);
            }
            return super.cancel(mayInterruptIfRunning);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy