|
|
@ -17,107 +17,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
package cn.hippo4j.core.executor;
|
|
|
|
package cn.hippo4j.core.executor;
|
|
|
|
|
|
|
|
|
|
|
|
import cn.hippo4j.common.config.ApplicationContextHolder;
|
|
|
|
import cn.hippo4j.common.toolkit.CollectionUtil;
|
|
|
|
import cn.hippo4j.core.executor.support.AbstractDynamicExecutorSupport;
|
|
|
|
import cn.hippo4j.core.plugin.impl.TaskDecoratorPlugin;
|
|
|
|
import cn.hippo4j.core.proxy.RejectedProxyUtil;
|
|
|
|
import cn.hippo4j.core.plugin.impl.TaskRejectCountRecordPlugin;
|
|
|
|
import cn.hippo4j.core.toolkit.SystemClock;
|
|
|
|
import cn.hippo4j.core.plugin.impl.TaskTimeoutNotifyAlarmPlugin;
|
|
|
|
import lombok.Getter;
|
|
|
|
import cn.hippo4j.core.plugin.impl.ThreadPoolExecutorShutdownPlugin;
|
|
|
|
|
|
|
|
import cn.hippo4j.core.plugin.manager.DefaultThreadPoolPluginManager;
|
|
|
|
|
|
|
|
import cn.hippo4j.core.plugin.manager.DefaultThreadPoolPluginRegistrar;
|
|
|
|
import lombok.NonNull;
|
|
|
|
import lombok.NonNull;
|
|
|
|
import lombok.Setter;
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
|
|
import org.springframework.beans.factory.DisposableBean;
|
|
|
|
import org.springframework.core.task.TaskDecorator;
|
|
|
|
import org.springframework.core.task.TaskDecorator;
|
|
|
|
|
|
|
|
|
|
|
|
import java.util.concurrent.*;
|
|
|
|
import java.util.Objects;
|
|
|
|
|
|
|
|
import java.util.concurrent.BlockingQueue;
|
|
|
|
|
|
|
|
import java.util.concurrent.RejectedExecutionHandler;
|
|
|
|
|
|
|
|
import java.util.concurrent.ThreadFactory;
|
|
|
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Enhanced dynamic and monitored thread pool.
|
|
|
|
* Enhanced dynamic and monitored thread pool.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public class DynamicThreadPoolExecutor extends AbstractDynamicExecutorSupport {
|
|
|
|
@Slf4j
|
|
|
|
|
|
|
|
public class DynamicThreadPoolExecutor extends ExtensibleThreadPoolExecutor implements DisposableBean {
|
|
|
|
|
|
|
|
|
|
|
|
@Getter
|
|
|
|
/**
|
|
|
|
@Setter
|
|
|
|
* Creates a new {@code DynamicThreadPoolExecutor} with the given initial parameters.
|
|
|
|
private Long executeTimeOut;
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param threadPoolId thread-pool id
|
|
|
|
@Getter
|
|
|
|
* @param executeTimeOut execute time out
|
|
|
|
@Setter
|
|
|
|
* @param waitForTasksToCompleteOnShutdown wait for tasks to complete on shutdown
|
|
|
|
private TaskDecorator taskDecorator;
|
|
|
|
* @param awaitTerminationMillis await termination millis
|
|
|
|
|
|
|
|
* @param corePoolSize the number of threads to keep in the pool, even
|
|
|
|
@Getter
|
|
|
|
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
|
|
|
|
@Setter
|
|
|
|
* @param maximumPoolSize the maximum number of threads to allow in the
|
|
|
|
private RejectedExecutionHandler redundancyHandler;
|
|
|
|
* pool
|
|
|
|
|
|
|
|
* @param keepAliveTime when the number of threads is greater than
|
|
|
|
@Getter
|
|
|
|
* the core, this is the maximum time that excess idle threads
|
|
|
|
private final String threadPoolId;
|
|
|
|
* will wait for new tasks before terminating.
|
|
|
|
|
|
|
|
* @param unit the time unit for the {@code keepAliveTime} argument
|
|
|
|
@Getter
|
|
|
|
* @param blockingQueue the queue to use for holding tasks before they are
|
|
|
|
private final AtomicLong rejectCount = new AtomicLong();
|
|
|
|
* executed. This queue will hold only the {@code Runnable}
|
|
|
|
|
|
|
|
* tasks submitted by the {@code execute} method.
|
|
|
|
private final ThreadLocal<Long> startTimeThreadLocal = new ThreadLocal<>();
|
|
|
|
* @param threadFactory the factory to use when the executor creates a new thread
|
|
|
|
|
|
|
|
* @param rejectedExecutionHandler the handler to use when execution is blocked because the thread bounds and queue capacities are reached
|
|
|
|
public DynamicThreadPoolExecutor(int corePoolSize,
|
|
|
|
* @throws IllegalArgumentException if one of the following holds:<br>
|
|
|
|
int maximumPoolSize,
|
|
|
|
* {@code corePoolSize < 0}<br>
|
|
|
|
long keepAliveTime,
|
|
|
|
* {@code keepAliveTime < 0}<br>
|
|
|
|
TimeUnit unit,
|
|
|
|
* {@code maximumPoolSize <= 0}<br>
|
|
|
|
long executeTimeOut,
|
|
|
|
* {@code maximumPoolSize < corePoolSize}
|
|
|
|
boolean waitForTasksToCompleteOnShutdown,
|
|
|
|
* @throws NullPointerException if {@code workQueue}
|
|
|
|
long awaitTerminationMillis,
|
|
|
|
* or {@code threadFactory} or {@code handler} is null
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public DynamicThreadPoolExecutor(
|
|
|
|
|
|
|
|
int corePoolSize, int maximumPoolSize,
|
|
|
|
|
|
|
|
long keepAliveTime, TimeUnit unit,
|
|
|
|
|
|
|
|
long executeTimeOut, boolean waitForTasksToCompleteOnShutdown, long awaitTerminationMillis,
|
|
|
|
@NonNull BlockingQueue<Runnable> blockingQueue,
|
|
|
|
@NonNull BlockingQueue<Runnable> blockingQueue,
|
|
|
|
@NonNull String threadPoolId,
|
|
|
|
@NonNull String threadPoolId,
|
|
|
|
@NonNull ThreadFactory threadFactory,
|
|
|
|
@NonNull ThreadFactory threadFactory,
|
|
|
|
@NonNull RejectedExecutionHandler rejectedExecutionHandler) {
|
|
|
|
@NonNull RejectedExecutionHandler rejectedExecutionHandler) {
|
|
|
|
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, waitForTasksToCompleteOnShutdown, awaitTerminationMillis, blockingQueue, threadPoolId, threadFactory, rejectedExecutionHandler);
|
|
|
|
super(
|
|
|
|
this.threadPoolId = threadPoolId;
|
|
|
|
threadPoolId, new DefaultThreadPoolPluginManager(),
|
|
|
|
this.executeTimeOut = executeTimeOut;
|
|
|
|
corePoolSize, maximumPoolSize, keepAliveTime, unit,
|
|
|
|
// Number of dynamic proxy denial policies.
|
|
|
|
blockingQueue, threadFactory, rejectedExecutionHandler);
|
|
|
|
RejectedExecutionHandler rejectedProxy = RejectedProxyUtil.createProxy(rejectedExecutionHandler, threadPoolId, rejectCount);
|
|
|
|
log.info("Initializing ExecutorService" + threadPoolId);
|
|
|
|
setRejectedExecutionHandler(rejectedProxy);
|
|
|
|
|
|
|
|
// Redundant fields to avoid reflecting the acquired fields when sending change information.
|
|
|
|
// init default plugins
|
|
|
|
redundancyHandler = rejectedExecutionHandler;
|
|
|
|
new DefaultThreadPoolPluginRegistrar(executeTimeOut, awaitTerminationMillis, waitForTasksToCompleteOnShutdown)
|
|
|
|
|
|
|
|
.doRegister(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Invoked by the containing {@code BeanFactory} on destruction of a bean.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public void execute(@NonNull Runnable command) {
|
|
|
|
public void destroy() {
|
|
|
|
if (taskDecorator != null) {
|
|
|
|
if (isWaitForTasksToCompleteOnShutdown()) {
|
|
|
|
command = taskDecorator.decorate(command);
|
|
|
|
super.shutdown();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
super.shutdownNow();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
super.execute(command);
|
|
|
|
getThreadPoolPluginManager().clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
/**
|
|
|
|
protected void beforeExecute(Thread t, Runnable r) {
|
|
|
|
* Get await termination millis.
|
|
|
|
if (executeTimeOut == null || executeTimeOut <= 0) {
|
|
|
|
*
|
|
|
|
return;
|
|
|
|
* @return await termination millis.
|
|
|
|
|
|
|
|
* @deprecated use {@link ThreadPoolExecutorShutdownPlugin}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
|
|
|
|
public long getAwaitTerminationMillis() {
|
|
|
|
|
|
|
|
return getPluginOfType(ThreadPoolExecutorShutdownPlugin.PLUGIN_NAME, ThreadPoolExecutorShutdownPlugin.class)
|
|
|
|
|
|
|
|
.map(ThreadPoolExecutorShutdownPlugin::getAwaitTerminationMillis)
|
|
|
|
|
|
|
|
.orElse(-1L);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
startTimeThreadLocal.set(SystemClock.now());
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Is wait for tasks to complete on shutdown.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @return true if instance wait for tasks to complete on shutdown, false other otherwise.
|
|
|
|
|
|
|
|
* @deprecated use {@link ThreadPoolExecutorShutdownPlugin}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
|
|
|
|
public boolean isWaitForTasksToCompleteOnShutdown() {
|
|
|
|
|
|
|
|
return getPluginOfType(ThreadPoolExecutorShutdownPlugin.PLUGIN_NAME, ThreadPoolExecutorShutdownPlugin.class)
|
|
|
|
|
|
|
|
.map(ThreadPoolExecutorShutdownPlugin::isWaitForTasksToCompleteOnShutdown)
|
|
|
|
|
|
|
|
.orElse(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
/**
|
|
|
|
protected void afterExecute(Runnable r, Throwable t) {
|
|
|
|
* Set support param.
|
|
|
|
Long startTime;
|
|
|
|
*
|
|
|
|
if ((startTime = startTimeThreadLocal.get()) == null) {
|
|
|
|
* @param awaitTerminationMillis await termination millis
|
|
|
|
return;
|
|
|
|
* @param waitForTasksToCompleteOnShutdown wait for tasks to complete on shutdown
|
|
|
|
|
|
|
|
* @deprecated use {@link ThreadPoolExecutorShutdownPlugin}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
|
|
|
|
public void setSupportParam(long awaitTerminationMillis, boolean waitForTasksToCompleteOnShutdown) {
|
|
|
|
|
|
|
|
getPluginOfType(ThreadPoolExecutorShutdownPlugin.PLUGIN_NAME, ThreadPoolExecutorShutdownPlugin.class)
|
|
|
|
|
|
|
|
.ifPresent(processor -> processor
|
|
|
|
|
|
|
|
.setAwaitTerminationMillis(awaitTerminationMillis)
|
|
|
|
|
|
|
|
.setWaitForTasksToCompleteOnShutdown(waitForTasksToCompleteOnShutdown));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Get reject count num.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @return reject count num
|
|
|
|
|
|
|
|
* @deprecated use {@link TaskRejectCountRecordPlugin}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
|
|
|
|
public Long getRejectCountNum() {
|
|
|
|
|
|
|
|
return getPluginOfType(TaskRejectCountRecordPlugin.PLUGIN_NAME, TaskRejectCountRecordPlugin.class)
|
|
|
|
|
|
|
|
.map(TaskRejectCountRecordPlugin::getRejectCountNum)
|
|
|
|
|
|
|
|
.orElse(-1L);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
|
|
|
|
long endTime = SystemClock.now();
|
|
|
|
/**
|
|
|
|
long executeTime;
|
|
|
|
* Get reject count.
|
|
|
|
boolean executeTimeAlarm = (executeTime = (endTime - startTime)) > executeTimeOut;
|
|
|
|
*
|
|
|
|
if (executeTimeAlarm && ApplicationContextHolder.getInstance() != null) {
|
|
|
|
* @return reject count num
|
|
|
|
ThreadPoolNotifyAlarmHandler notifyAlarmHandler = ApplicationContextHolder.getBean(ThreadPoolNotifyAlarmHandler.class);
|
|
|
|
* @deprecated use {@link TaskRejectCountRecordPlugin}
|
|
|
|
if (notifyAlarmHandler != null) {
|
|
|
|
*/
|
|
|
|
notifyAlarmHandler.asyncSendExecuteTimeOutAlarm(threadPoolId, executeTime, executeTimeOut, this);
|
|
|
|
@Deprecated
|
|
|
|
|
|
|
|
public AtomicLong getRejectCount() {
|
|
|
|
|
|
|
|
return getPluginOfType(TaskRejectCountRecordPlugin.PLUGIN_NAME, TaskRejectCountRecordPlugin.class)
|
|
|
|
|
|
|
|
.map(TaskRejectCountRecordPlugin::getRejectCount)
|
|
|
|
|
|
|
|
.orElse(new AtomicLong(0));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Get execute time out.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @deprecated use {@link TaskTimeoutNotifyAlarmPlugin}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
|
|
|
|
public Long getExecuteTimeOut() {
|
|
|
|
|
|
|
|
return getPluginOfType(TaskTimeoutNotifyAlarmPlugin.PLUGIN_NAME, TaskTimeoutNotifyAlarmPlugin.class)
|
|
|
|
|
|
|
|
.map(TaskTimeoutNotifyAlarmPlugin::getExecuteTimeOut)
|
|
|
|
|
|
|
|
.orElse(-1L);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Set execute time out.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param executeTimeOut execute time out
|
|
|
|
|
|
|
|
* @deprecated use {@link TaskTimeoutNotifyAlarmPlugin}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
|
|
|
|
public void setExecuteTimeOut(Long executeTimeOut) {
|
|
|
|
|
|
|
|
getPluginOfType(TaskTimeoutNotifyAlarmPlugin.PLUGIN_NAME, TaskTimeoutNotifyAlarmPlugin.class)
|
|
|
|
|
|
|
|
.ifPresent(processor -> processor.setExecuteTimeOut(executeTimeOut));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Get {@link TaskDecorator}.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @deprecated use {@link TaskDecoratorPlugin}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
|
|
|
|
public TaskDecorator getTaskDecorator() {
|
|
|
|
|
|
|
|
return getPluginOfType(TaskDecoratorPlugin.PLUGIN_NAME, TaskDecoratorPlugin.class)
|
|
|
|
|
|
|
|
.map(processor -> CollectionUtil.getFirst(processor.getDecorators()))
|
|
|
|
|
|
|
|
.orElse(null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
|
|
|
|
startTimeThreadLocal.remove();
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Set {@link TaskDecorator}.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param taskDecorator task decorator
|
|
|
|
|
|
|
|
* @deprecated use {@link TaskDecoratorPlugin}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
|
|
|
|
public void setTaskDecorator(TaskDecorator taskDecorator) {
|
|
|
|
|
|
|
|
getPluginOfType(TaskDecoratorPlugin.PLUGIN_NAME, TaskDecoratorPlugin.class)
|
|
|
|
|
|
|
|
.ifPresent(processor -> {
|
|
|
|
|
|
|
|
if (Objects.nonNull(taskDecorator)) {
|
|
|
|
|
|
|
|
processor.clearDecorators();
|
|
|
|
|
|
|
|
processor.addDecorator(taskDecorator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
/**
|
|
|
|
protected ExecutorService initializeExecutor() {
|
|
|
|
* Get rejected execution handler.
|
|
|
|
return this;
|
|
|
|
*
|
|
|
|
|
|
|
|
* @deprecated use {@link DynamicThreadPoolExecutor#getRejectedExecutionHandler}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
|
|
|
|
public RejectedExecutionHandler getRedundancyHandler() {
|
|
|
|
|
|
|
|
return getRejectedExecutionHandler();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Long getRejectCountNum() {
|
|
|
|
/**
|
|
|
|
return rejectCount.get();
|
|
|
|
* Set rejected execution handler.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param handler handler
|
|
|
|
|
|
|
|
* @deprecated use {@link DynamicThreadPoolExecutor#setRejectedExecutionHandler}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
@Deprecated
|
|
|
|
|
|
|
|
public void setRedundancyHandler(RejectedExecutionHandler handler) {
|
|
|
|
|
|
|
|
setRejectedExecutionHandler(handler);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|