mirror of https://github.com/longtai-cn/hippo4j
parent
5f68ec2e0c
commit
7f4763ff51
@ -0,0 +1,147 @@
|
|||||||
|
package cn.hippo4j.starter.core;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.BeanNameAware;
|
||||||
|
import org.springframework.beans.factory.DisposableBean;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamic executor configuration support.
|
||||||
|
*
|
||||||
|
* @author chen.ma
|
||||||
|
* @date 2021/11/28 12:17
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public abstract class DynamicExecutorConfigurationSupport extends ThreadPoolExecutor
|
||||||
|
implements BeanNameAware, InitializingBean, DisposableBean {
|
||||||
|
|
||||||
|
private String beanName;
|
||||||
|
|
||||||
|
private ExecutorService executor;
|
||||||
|
|
||||||
|
private long awaitTerminationMillis = 0;
|
||||||
|
|
||||||
|
private boolean waitForTasksToCompleteOnShutdown = false;
|
||||||
|
|
||||||
|
public DynamicExecutorConfigurationSupport(int corePoolSize,
|
||||||
|
int maximumPoolSize,
|
||||||
|
long keepAliveTime,
|
||||||
|
TimeUnit unit,
|
||||||
|
boolean waitForTasksToCompleteOnShutdown,
|
||||||
|
long awaitTerminationMillis,
|
||||||
|
BlockingQueue<Runnable> workQueue,
|
||||||
|
ThreadFactory threadFactory,
|
||||||
|
RejectedExecutionHandler handler) {
|
||||||
|
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
|
||||||
|
this.waitForTasksToCompleteOnShutdown = waitForTasksToCompleteOnShutdown;
|
||||||
|
this.awaitTerminationMillis = awaitTerminationMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the target {@link java.util.concurrent.ExecutorService} instance.
|
||||||
|
* Called by {@code afterPropertiesSet}.
|
||||||
|
*
|
||||||
|
* @return a new ExecutorService instance
|
||||||
|
* @see #afterPropertiesSet()
|
||||||
|
*/
|
||||||
|
protected abstract ExecutorService initializeExecutor();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBeanName(String name) {
|
||||||
|
this.beanName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls {@code initialize()} after the container applied all property values.
|
||||||
|
*
|
||||||
|
* @see #initialize()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() {
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls {@code shutdown} when the BeanFactory destroys.
|
||||||
|
* the task executor instance.
|
||||||
|
*
|
||||||
|
* @see #shutdown()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
shutdownSupport();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the ExecutorService.
|
||||||
|
*/
|
||||||
|
public void initialize() {
|
||||||
|
if (log.isInfoEnabled()) {
|
||||||
|
log.info("Initializing ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.executor = initializeExecutor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a shutdown on the underlying ExecutorService.
|
||||||
|
*
|
||||||
|
* @see java.util.concurrent.ExecutorService#shutdown()
|
||||||
|
* @see java.util.concurrent.ExecutorService#shutdownNow()
|
||||||
|
*/
|
||||||
|
public void shutdownSupport() {
|
||||||
|
if (log.isInfoEnabled()) {
|
||||||
|
log.info("Shutting down ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
|
||||||
|
}
|
||||||
|
if (this.executor != null) {
|
||||||
|
if (this.waitForTasksToCompleteOnShutdown) {
|
||||||
|
this.executor.shutdown();
|
||||||
|
} else {
|
||||||
|
for (Runnable remainingTask : this.executor.shutdownNow()) {
|
||||||
|
cancelRemainingTask(remainingTask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
awaitTerminationIfNecessary(this.executor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel the given remaining task which never commended execution,
|
||||||
|
* as returned from {@link ExecutorService#shutdownNow()}.
|
||||||
|
*
|
||||||
|
* @param task the task to cancel (typically a {@link RunnableFuture})
|
||||||
|
* @see #shutdown()
|
||||||
|
* @see RunnableFuture#cancel(boolean)
|
||||||
|
* @since 5.0.5
|
||||||
|
*/
|
||||||
|
protected void cancelRemainingTask(Runnable task) {
|
||||||
|
if (task instanceof Future) {
|
||||||
|
((Future<?>) task).cancel(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for the executor to terminate, according to the value of the.
|
||||||
|
*/
|
||||||
|
private void awaitTerminationIfNecessary(ExecutorService executor) {
|
||||||
|
if (this.awaitTerminationMillis > 0) {
|
||||||
|
try {
|
||||||
|
if (!executor.awaitTermination(this.awaitTerminationMillis, TimeUnit.MILLISECONDS)) {
|
||||||
|
if (log.isWarnEnabled()) {
|
||||||
|
log.warn("Timed out while waiting for executor" +
|
||||||
|
(this.beanName != null ? " '" + this.beanName + "'" : "") + " to terminate");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
if (log.isWarnEnabled()) {
|
||||||
|
log.warn("Interrupted while waiting for executor" +
|
||||||
|
(this.beanName != null ? " '" + this.beanName + "'" : "") + " to terminate");
|
||||||
|
}
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in new issue