首页 > 解决方案 > 在 Java 中运行指定时间段的脚本

问题描述

我有一个要运行的 java 代码。如果作业没有在 2 小时内完成,那么它应该被自动终止(基本上是某种定时批处理)。

如何在 Java 中实现这一点?

标签: java

解决方案


如果您使用的是 Java 9 或更高版本,则可以执行超时批处理,如下所示:-

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(this::longRunningTask)
                       .orTimeout(2, TimeUnit.SECONDS); 
 future.get(); // j.u.c.ExecutionException after waiting for 2 second

如果它在timeout限制内完成,它将返回值(这里是一个Integer响应future.get()方法的对象)

而且,这个批处理是异步的(如果你没有显式调用 get 方法。)

注意:这不会阻止线程完成任务,它只是在主线程中完成一个带有超时异常的未来,以便主线程可以继续。后台任务/线程仍在继续完成。(看@Andreas 评论)

一些样品:-

final CompletableFuture<Void> future =
                   CompletableFuture.supplyAsync(this::longRunningTask)
                                    .orTimeout(2, TimeUnit.SECONDS);

future.get(); // j.u.c.ExecutionException after waiting for 2 second

还有longRunningTask():-

private Void longRunningTask(){
    log.info("Thread name" + Thread.currentThread().getName());
    try {
        log.info("Going to sleep for 10 sec...");
        Thread.sleep(10*1000);
        log.info("Sleep Completed. Task Completed.");
    } catch (InterruptedException e) {
        log.info("Exception Occurred");
    }
    finally{
        log.info("Final Cleanup in progress.");
    }
    log.info("Finishing the long task.");
    return null;
}

如果您运行上面的代码,它会在主线程(future.get()被调用的地方)中给出执行异常,但在完成 10 秒睡眠后longRunningTask仍会打印。Sleep Completed. Task Completed.

如果你仔细注意到,longRunnigThread它永远不会被中断(不会进入 catch 块)所以会正常继续,但主线程会在get().

解决方法/解决方案:

使用ExecutorService并提交 longRunnigTask 未来Exceutor,如果发生超时,关闭执行器,否则,get()在没有超时异常的情况下成功后关闭。

样本:

    ExecutorService myWorkers = Executors.newFixedThreadPool(1);

    final CompletableFuture<Void> longTask = 
            CompletableFuture.supplyAsync(this::longRunningTask, myWorkers)
                .orTimeout(2, TimeUnit.SECONDS);

    try {
        longTask.get();
    } catch (InterruptedException | ExecutionException e) {
        log.info("EE... Kill the executor thread/s.");
        myWorkers.shutdownNow(); // this will interrupt the thread, catch the IntrExcep in thread and return the execution there
    }

和稍作修改longRunnigTask

private Void longRunningTask(){
    log.info("Thread name" + Thread.currentThread().getName());
    try {
        log.info("Going to sleep for 10 sec...");
        Thread.sleep(10*1000);
        log.info("Sleep Completed. Task Completed.");
    } catch (InterruptedException e) {
        log.info("Exception Occurred");
        return null; // this will finish the thread exce releasing all locking resources. Can be GCed then.
    }
    finally{
        log.info("Final Cleanup in progress.");
    }
    log.info("Finishing the long task.");
    return null;
}

使用这种方法,它不会完成任务 inf 超时发生(您不会Sleep completed. Task completed.在日志中看到..),并且会exception occurredlongRunningTask线程中看到(因为由 引起的中断myWorker.shutdown)。


推荐阅读