停止Spring计划执行,如果它在一段固定时间后挂起

Sha*_*ams 13 java spring spring-scheduled spring-boot

我使用Spring Framework Scheduled来安排我的工作使用cron每5分钟运行一次.但有时我的工作无限期地等待外部资源,我不能把超时放在那里.我不能fixedDelay像以前的过程一样进入等待无限模式,我必须每隔5分钟刷新一次数据.

所以我在Spring框架中寻找任何一个选项来在它成功运行Scheduled之后停止该进程/线程fixed-time.

我发现下面的设置初始化ThreadPoolExecutor为120秒keepAliveTime,我把它放在@Configuration课堂上.任何人都能告诉我这项工作是否符合我的预期.

@Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
    int coreThreads = 8;
    int maxThreads = 20;
    final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            coreThreads, maxThreads, 120L, 
            TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()
    );
    threadPoolExecutor.allowCoreThreadTimeOut(true);

    return threadPoolExecutor;
}
Run Code Online (Sandbox Code Playgroud)

JEY*_*JEY 8

我不确定这会按预期工作.确实keepAlive用于IDLE线程,我不知道你的等待资源的线程是否处于IDLE状态.此外,只有当线程数大于核心时,除非您监视线程池,否则您无法确切知道它何时发生.

keepAliveTime - 当线程数大于核心时,这是多余空闲线程在终止之前等待新任务的最长时间.

你能做的是以下几点:

public class MyTask {

    private final long timeout;

    public MyTask(long timeout) {
        this.timeout = timeout;
    }

    @Scheduled(cron = "")
    public void cronTask() {
        Future<Object> result = doSomething();
        result.get(timeout, TimeUnit.MILLISECONDS);
    }

    @Async
    Future<Object> doSomething() {
        //what i should do
        //get ressources etc...
    }
}
Run Code Online (Sandbox Code Playgroud)

不要忘记添加@EnableAsync

通过实现Callable,也可以在没有@Async的情况下执行相同的操作.

编辑:请记住,它将等到超时,但运行任务的线程不会被中断.发生TimeoutException时,您需要调用Future.cancel.并在任务中检查isInterrupted()以停止处理.如果您正在调用api,请确保选中isInterrupted().


小智 7

allowCoreThreadTimeOuttimeout设置没有帮助导致它只允许工作线程在一段时间后无法工作(参见javadocs)

你说你的工作无限期地等待外部资源.我确定这是因为您(或您使用的某些第三方库)使用的套接字默认为超时无限.还要记住jvm在socket.connect/read上阻塞时忽略了Thread.interrupt().

因此,找出您的任务中使用的女巫套接字库(以及它是如何使用的)并更改它的默认超时设置.

例如:RestTemplate在Spring内部广泛使用(在休息客户端,春季社交,春季安全OAuth等).并且有ClientHttpRequestFactory实现来创建RestTemplate实例.默认情况下,spring使用SimpleClientHttpRequestFactory,它使用JDK套接字.默认情况下,所有超时都是无限的.

因此,找出你准确冻结的位置,阅读它的文档并正确配置它.

PS如果你没有足够的时间和"感觉幸运"尝试运行你的应用程序将jvm属性sun.net.client.defaultConnectTimeoutsun.net.client.defaultReadTimeout设置为一些合理的值(有关更多详细信息,请参阅文档)