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

org.jgroups.util.AsyncExecutor Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote Jakarta Enterprise Beans and Jakarta Messaging, including all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and Jakarta Messaging BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

The newest version!
package org.jgroups.util;

import org.jgroups.Lifecycle;
import org.jgroups.annotations.ManagedAttribute;
import org.jgroups.annotations.Property;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Supplier;

import static org.jgroups.conf.AttributeType.SCALAR;

/**
 * Used to execute asynchronous tasks, e.g. async-send (https://issues.redhat.com/browse/JGRP-2603). Uses a blockng
 * queue and a dequeuer thread, which passes removed tasks to the thread pool
 * @author Bela Ban
 * @since  5.3.5
 */
public class AsyncExecutor implements Lifecycle {

    @Property(description="If not enabled, tasks will executed on the runner's thread")
    protected boolean         enabled=true;

    @ManagedAttribute(description="Total number of times a message was sent (includes rejected messages)",type=SCALAR)
    protected final LongAdder num_sends=new LongAdder();

    @ManagedAttribute(description="Number of rejected message due to an exhausted thread pool (includes dropped " +
      "messages and messages sent on the caller's thread",type=SCALAR)
    protected final LongAdder num_rejected=new LongAdder();

    @ManagedAttribute(description="Number of dropped tasks (when DONT_BLOCK flag is set in the message)",type=SCALAR)
    protected final LongAdder num_drops_on_full_thread_pool=new LongAdder();

    @ManagedAttribute(description="Messages that were sent on the caller's thread due to an exhausted pool",type=SCALAR)
    protected final LongAdder num_sends_on_callers_thread=new LongAdder();

    protected ThreadPool      thread_pool;
    protected Executor        executor;

    public boolean          enabled()                  {return enabled;}
    public AsyncExecutor enable(boolean b)          {enabled=b; return this;}
    public ThreadPool       threadPool()               {return thread_pool;}
    public AsyncExecutor threadPool(ThreadPool p)   {this.thread_pool=p; return this;}
    public long             numSends()                 {return num_sends.sum();}
    public long             numSendsOnCallersThread()  {return num_sends_on_callers_thread.sum();}
    public long             numDropsOnFullThreadPool() {return num_drops_on_full_thread_pool.sum();}
    public long             numRejected()              {return num_rejected.sum();}


    public AsyncExecutor() {
    }

    public AsyncExecutor(ThreadPool p) {
        this.thread_pool=p;
    }

    public void resetStats() {
        num_sends.reset();
        num_rejected.reset();
        num_drops_on_full_thread_pool.reset();
        num_sends_on_callers_thread.reset();
    }

    public CompletableFuture execute(Supplier t, boolean can_be_dropped) {
        Task task=new Task<>(t, new CompletableFuture<>());
        Executor exec=executor;
        try {
            num_sends.increment();
            if(enabled && (exec=exec()) != null)
                return CompletableFuture.supplyAsync(t, exec);
            return CompletableFuture.completedFuture(t.get());
        }
        catch(RejectedExecutionException ex) {
            num_rejected.increment();
            if(!can_be_dropped) {
                task.run(); // if we cannot drop the task, run it on the caller thread
                num_sends_on_callers_thread.increment();
            }
            else {
                task.completeExceptionally(ex);
                num_drops_on_full_thread_pool.increment();
            }
        }
        return task.cf;
    }

    @Override
    public String toString() {
        return String.format("rejected: %,d, drops=%,d, sends_on_caller: %,d, pool: %s\n",
                             num_rejected.sum(), num_drops_on_full_thread_pool.sum(), num_sends_on_callers_thread.sum(),
                             thread_pool.toString());
    }

    protected Executor exec() {
        Executor exec=executor;
        return exec != null? exec : (exec=executor=thread_pool.pool());
    }


    protected static class Task implements Runnable {
        protected final Supplier        task;
        protected final CompletableFuture cf;

        protected Task(Supplier task, CompletableFuture cf) {
            this.task=task;
            this.cf=cf;
        }

        protected Task completeExceptionally(Throwable t) {
            cf.completeExceptionally(t);
            return this;
        }

        @Override
        public void run() {
            try {
                T result=task.get();
                cf.complete(result);
            }
            catch(Throwable t) {
                cf.completeExceptionally(t);
            }
        }
    }



}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy