host.anzo.commons.threading.ThreadPool Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of commons-core Show documentation
Show all versions of commons-core Show documentation
Commons library to make me happy.
package host.anzo.commons.threading;
import de.mxro.metrics.jre.Metrics;
import delight.async.properties.PropertyNode;
import host.anzo.commons.emergency.metric.IMetric;
import host.anzo.commons.emergency.metric.Metric;
import host.anzo.commons.emergency.metric.MetricGroupType;
import host.anzo.commons.emergency.metric.MetricResult;
import host.anzo.core.config.EmergencyConfig;
import host.anzo.core.startup.EShutdownPriority;
import host.anzo.core.startup.IShutdownable;
import host.anzo.core.startup.StartupComponent;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.text.TextStringBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author ANZO
* @since 8/19/2021
*/
@Slf4j
@Metric
@StartupComponent(value = "Threading", shutdownPriority = EShutdownPriority.MINOR)
public final class ThreadPool implements IShutdownable, IMetric {
@Getter(lazy = true)
private static final ThreadPool instance = new ThreadPool();
private @Getter final ScheduledThreadPoolExecutor generalThreadPool;
private final ScheduledFuture> purgeTask;
private final AtomicBoolean shutdowning = new AtomicBoolean(false);
private final static PropertyNode scheduleMetrics = Metrics.create();
private final static PropertyNode executeMetrics = Metrics.create();
private ThreadPool() {
generalThreadPool = new ScheduledThreadPoolExecutor(Math.max(1, Runtime.getRuntime().availableProcessors() / 2), new ThreadPoolPriorityFactory("GeneralSTPool", Thread.NORM_PRIORITY));
generalThreadPool.allowCoreThreadTimeOut(false);
generalThreadPool.setRemoveOnCancelPolicy(true);
generalThreadPool.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
purgeTask = scheduleGeneralAtFixedRate("ThreadPool.PurgeTask()", new PurgeTask(), 5, 5, TimeUnit.MINUTES);
log.info("ThreadPool initialized:");
log.info("- GeneralPoolCoreSize: {}/{}", generalThreadPool.getCorePoolSize(), generalThreadPool.getMaximumPoolSize());
}
/**
* Schedules a general task to be executed after the given delay.
* @param name task name
* @param task the task to execute
* @param delay the delay in the given time unit
* @param unit the time unit of the delay parameter
* @return a ScheduledFuture representing pending completion of the task, and whose get() method will throw an exception upon cancellation
*/
public @Nullable ScheduledFuture> scheduleGeneral(String name, Runnable task, long delay, TimeUnit unit) {
if (shutdowning.get()) {
return null;
}
try {
if (EmergencyConfig.ENABLE_METRICS) {
scheduleMetrics.record(Metrics.happened(name));
}
return generalThreadPool.schedule(new RunnableWrapper(task), delay, unit);
} catch (RejectedExecutionException ignored) {
return null;
}
}
public @Nullable ScheduledFuture> scheduleGeneral(String name, Runnable task, @NotNull LocalDateTime dateTime) {
long deadLine = dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
long delay = deadLine - System.currentTimeMillis();
if (delay > 0) {
if (EmergencyConfig.ENABLE_METRICS) {
scheduleMetrics.record(Metrics.happened(name));
}
return scheduleGeneral(name, task, delay, TimeUnit.MILLISECONDS);
}
return null;
}
/**
* Schedules a general task to be executed at fixed rate.
*
* @param name task name
* @param task the task to execute
* @param initialDelay the initial delay in the given time unit
* @param period the period between executions in the given time unit
* @param unit the time unit of the initialDelay and period parameters
* @return a ScheduledFuture representing pending completion of the task, and whose get() method will throw an exception upon cancellation
*/
public @Nullable ScheduledFuture> scheduleGeneralAtFixedRate(String name, Runnable task, long initialDelay, long period, TimeUnit unit) {
if (shutdowning.get()) {
return null;
}
try {
if (EmergencyConfig.ENABLE_METRICS) {
scheduleMetrics.record(Metrics.happened(name));
}
return generalThreadPool.scheduleAtFixedRate(new RunnableWrapper(task), initialDelay, period, unit);
} catch (RejectedExecutionException ignored) {
return null;
}
}
/**
* Executes an general task sometime in future in another thread.
* @param name task name
* @param task the task to execute
*/
public void executeGeneral(String name, Runnable task) {
if (shutdowning.get()) {
return;
}
try {
if (EmergencyConfig.ENABLE_METRICS) {
executeMetrics.record(Metrics.happened(name));
}
generalThreadPool.execute(new RunnableWrapper(task));
} catch (RejectedExecutionException ignored) {
}
}
public @NotNull String getStats() {
final TextStringBuilder builder = new TextStringBuilder();
builder.appendln(" | -------");
builder.appendln(" + General:");
builder.appendln(" |- ActiveThreads: " + generalThreadPool.getActiveCount());
builder.appendln(" |- getCorePoolSize: " + generalThreadPool.getCorePoolSize());
builder.appendln(" |- PoolSize: " + generalThreadPool.getPoolSize());
builder.appendln(" |- MaximumPoolSize: " + generalThreadPool.getMaximumPoolSize());
builder.appendln(" |- CompletedTasks: " + generalThreadPool.getCompletedTaskCount());
builder.appendln(" |- ScheduledTasks: " + generalThreadPool.getQueue().size());
builder.appendln(" | -------");
return builder.toString();
}
@Override
public void onShutdown() {
if (shutdowning.compareAndSet(false, true)) {
try {
purgeTask.cancel(false);
generalThreadPool.shutdown();
generalThreadPool.purge();
if (!generalThreadPool.awaitTermination(120, TimeUnit.SECONDS)) {
generalThreadPool.shutdownNow();
}
log.info("All ThreadPools are now stopped");
} catch (InterruptedException e) {
log.warn("There has been a problem shutting down the thread pool manager!", e);
}
}
}
@Override
public @NotNull List getMetric() {
final List metricResults = new ArrayList<>();
final MetricResult scheduleResult = new MetricResult();
scheduleResult.setMetricGroupType(MetricGroupType.THREADPOOL);
scheduleResult.setName("Schedule");
scheduleResult.setData(scheduleMetrics.render().get());
metricResults.add(scheduleResult);
final MetricResult executeResult = new MetricResult();
executeResult.setMetricGroupType(MetricGroupType.THREADPOOL);
executeResult.setName("Execute");
executeResult.setData(executeMetrics.render().get());
metricResults.add(executeResult);
return metricResults;
}
private class PurgeTask implements Runnable {
@Override
public void run() {
generalThreadPool.purge();
}
}
}