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

org.jgroups.util.ThreadPool 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.Address;
import org.jgroups.Global;
import org.jgroups.Lifecycle;
import org.jgroups.annotations.ManagedAttribute;
import org.jgroups.annotations.Property;
import org.jgroups.conf.AttributeType;
import org.jgroups.logging.Log;
import org.jgroups.logging.LogFactory;

import java.util.concurrent.*;
import java.util.concurrent.atomic.LongAdder;

import static org.jgroups.conf.AttributeType.SCALAR;
import static org.jgroups.conf.AttributeType.TIME;
import static org.jgroups.util.SuppressLog.Level.warn;

/**
 * Thread pool based on {@link java.util.concurrent.ThreadPoolExecutor}
 * @author Bela Ban
 * @since  5.2
 */
public class ThreadPool implements Lifecycle {
    protected Executor            thread_pool;
    protected Log                 log;
    protected ThreadFactory       thread_factory;
    protected Address             address;
    protected SuppressLog thread_pool_full_log;

    @Property(description="Whether or not the thread pool is enabled. If false, tasks will be run on the caller's thread")
    protected boolean             enabled=true;

    @Property(description="If true, create virtual threads, otherwise create native threads")
    protected boolean             use_virtual_threads;

    @Property(description="Minimum thread pool size for the thread pool")
    protected int                 min_threads;

    @Property(description="Maximum thread pool size for the thread pool")
    protected int                 max_threads=200;

    @Property(description="Timeout (ms) to remove idle threads from the pool", type=AttributeType.TIME)
    protected long                keep_alive_time=30000;

    @Property(description="The rejection policy to be used in the thread pool (abort, discard, run, custom etc. " +
      "See Util.parseRejectionPolicy() for details")
    protected String              rejection_policy="abort";

    @Property(description="Time (in milliseconds) during which thread-pool full messages are suppressed",type=TIME)
    protected long                thread_pool_full_suppress_time=60_000;

    @Property(description="The number of times a thread pool needs to be full before a thread dump is logged",
    deprecatedMessage="ignored")
    @Deprecated(since="5.4")
    protected int                 thread_dumps_threshold=1;

    @Property(description="Path to which the thread dump will be written. Ignored if null",
      systemProperty="jgroups.threaddump.path",deprecatedMessage="ignored")
    @Deprecated(since="5.4")
    protected String              thread_dump_path;

    @Property(description="Dump threads when the thread pool is full")
    protected boolean             thread_dumps_enabled;

    @Property(description="Increases max_threads by the view size + delta if enabled " +
      "(https://issues.redhat.com/browse/JGRP-2655)")
    protected boolean             increase_max_size_dynamically=true;

    @Property(description="If the view is greater than the max thread pool size, the latter is set to " +
      "view size + delta. Only enabled if increase_max_size_dynamically is true")
    protected int                 delta=10;

    @ManagedAttribute(description="The number of messages dropped because the thread pool was full",type= SCALAR)
    protected final LongAdder     num_rejected_msgs=new LongAdder();

    public ThreadPool() {
    }

    public boolean isEnabled() {return enabled;}

    public Executor getThreadPool() {
        return thread_pool;
    }

    public ThreadPool setThreadPool(Executor thread_pool) {
        if(this.thread_pool != null)
            destroy();
        this.thread_pool=thread_pool;
        return this;
    }

    public ThreadPool setThreadFactory(ThreadFactory factory) {
        this.thread_factory=factory;
        if(thread_pool instanceof ThreadPoolExecutor)
            ((ThreadPoolExecutor)thread_pool).setThreadFactory(factory);
        return this;
    }

    public ThreadFactory getThreadFactory() {return thread_factory;}

    public boolean isShutdown() {
        return thread_pool instanceof ExecutorService && ((ExecutorService)thread_pool).isShutdown();
    }

    public int getMinThreads() {return min_threads;}

    public ThreadPool setMinThreads(int size) {
        min_threads=size;
        if(thread_pool instanceof ThreadPoolExecutor)
            ((ThreadPoolExecutor)thread_pool).setCorePoolSize(size);
        return this;
    }

    public int getMaxThreads() {return max_threads;}

    public ThreadPool setMaxThreads(int size) {
        max_threads=size;
        if(thread_pool instanceof ThreadPoolExecutor)
            ((ThreadPoolExecutor)thread_pool).setMaximumPoolSize(size);
        return this;
    }

    public long getKeepAliveTime() {return keep_alive_time;}

    public ThreadPool setKeepAliveTime(long time) {
        keep_alive_time=time;
        if(thread_pool instanceof ThreadPoolExecutor)
            ((ThreadPoolExecutor)thread_pool).setKeepAliveTime(time, TimeUnit.MILLISECONDS);
        return this;
    }

    public ThreadPool setRejectionPolicy(String policy) {
        RejectedExecutionHandler p=Util.parseRejectionPolicy(policy);
        this.rejection_policy=policy;
        if(thread_pool instanceof ThreadPoolExecutor)
            ((ThreadPoolExecutor)thread_pool).setRejectedExecutionHandler(p);
        return this;
    }

    public RejectedExecutionHandler getRejectedExecutionHandler() {
        Executor t=thread_pool;
        return t instanceof ThreadPoolExecutor? ((ThreadPoolExecutor)t).getRejectedExecutionHandler() : null;
    }

    public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
        if(thread_pool instanceof ThreadPoolExecutor)
            ((ThreadPoolExecutor)thread_pool).setRejectedExecutionHandler(handler);
    }

    public long       getThreadPoolFullSuppressTime()          {return thread_pool_full_suppress_time;}
    public ThreadPool setThreadPoolFullSuppressTime(long t)    {this.thread_pool_full_suppress_time=t; return this;}
    public boolean    getThreadDumpsEnabled()                  {return thread_dumps_enabled;}
    public ThreadPool setThreadDumpsEnabled(boolean b)         {thread_dumps_enabled=b; return this;}
    @Deprecated public int        getThreadDumpsThreshold()    {return 0;}
    @Deprecated public ThreadPool setThreadDumpsThreshold(int t) {return this;}
    public Address    getAddress()                             {return address;}
    public ThreadPool setAddress(Address a)                    {this.address=a; return this;}
    public boolean    getIncreaseMaxSizeDynamically()          {return increase_max_size_dynamically;}
    public ThreadPool setIncreaseMaxSizeDynamically(boolean b) {increase_max_size_dynamically=b; return this;}
    public int        getDelta()                               {return delta;}
    public ThreadPool setDelta(int d)                          {delta=d; return this;}
    public long       numberOfRejectedMessages()               {return num_rejected_msgs.sum();}
    public ThreadPool log(Log l)                               {log=l; return this;}
    public boolean    useVirtualThreads()                      {return use_virtual_threads;}
    public ThreadPool useVirtualThreads(boolean b)             {use_virtual_threads=b; return this;}

    @Deprecated public int  getNumberOfThreadDumps() {return -1;}
    @Deprecated public void resetThreadDumps() {}

    @ManagedAttribute(description="Current number of threads in the thread pool",type=SCALAR)
    public int getThreadPoolSize() {
        if(thread_pool instanceof ThreadPoolExecutor)
            return ((ThreadPoolExecutor)thread_pool).getPoolSize();
        return 0;
    }

    @ManagedAttribute(description="Current number of active threads in the thread pool",type=SCALAR)
    public int getThreadPoolSizeActive() {
        if(thread_pool instanceof ThreadPoolExecutor)
            return ((ThreadPoolExecutor)thread_pool).getActiveCount();
        return 0;
    }

    @ManagedAttribute(description="Largest number of threads in the thread pool",type=SCALAR)
    public int getLargestSize() {
        if(thread_pool instanceof ThreadPoolExecutor)
            return ((ThreadPoolExecutor)thread_pool).getLargestPoolSize();
        return 0;
    }

    public void resetStats() {
        num_rejected_msgs.reset();
    }


    @Override
    public void init() throws Exception {
        if(log == null)
            log=LogFactory.getLog(getClass());
        thread_pool_full_log=new SuppressLog<>(log, "ThreadPoolFull");
        if(enabled) {
            if(thread_factory == null)
                thread_factory=new DefaultThreadFactory("thread-pool", true, true);
            thread_pool=ThreadCreator.createThreadPool(min_threads, max_threads, keep_alive_time,
                                  rejection_policy, new SynchronousQueue<>(), thread_factory, use_virtual_threads, log);
        }
        else // otherwise use the caller's thread to unmarshal the byte buffer into a message
            thread_pool=new DirectExecutor();
    }

    @Override
    public void destroy() {
        if(thread_pool instanceof ExecutorService) {
            ExecutorService service=(ExecutorService)thread_pool;
            service.shutdownNow();
            try {
                service.awaitTermination(Global.THREADPOOL_SHUTDOWN_WAIT_TIME, TimeUnit.MILLISECONDS);
            }
            catch(InterruptedException ignored) {
            }
        }
    }

    public ThreadPool removeExpired() {
        thread_pool_full_log.removeExpired(thread_pool_full_suppress_time);
        return this;
    }

    public void doExecute(Runnable task) {
        thread_pool.execute(task);
    }

    public Executor pool() {return thread_pool;}

    public boolean execute(Runnable task) {
        try {
            thread_pool.execute(task);
            return true;
        }
        catch(RejectedExecutionException ex) {
            num_rejected_msgs.increment();
            //https://issues.redhat.com/browse/JGRP-2802
            String thread_dump=thread_dumps_enabled? String.format(". Threads:\n%s", Util.dumpThreads()) : "";
            thread_pool_full_log.log(warn, "thread-pool-full", thread_pool_full_suppress_time,
                                     address, max_threads, getThreadPoolSize(), thread_dump);
            return false;
        }
        catch(Throwable t) {
            log.error("failure submitting task to thread pool", t);
            num_rejected_msgs.increment();
            return false;
        }
    }

    public String toString() {
        return thread_pool != null? thread_pool.toString() : "n/a";
    }

    protected static ExecutorService createThreadPool(int min_threads, int max_threads, long keep_alive_time,
                                                      String rejection_policy,
                                                      BlockingQueue queue, final ThreadFactory factory) {
        ThreadPoolExecutor pool=new ThreadPoolExecutor(min_threads, max_threads, keep_alive_time, TimeUnit.MILLISECONDS,
                                                       queue, factory);
        RejectedExecutionHandler handler=Util.parseRejectionPolicy(rejection_policy);
        pool.setRejectedExecutionHandler(new ShutdownRejectedExecutionHandler(handler));
        return pool;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy