Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在java中计划单线程重复运行,但如果上一次运行未完成,则跳过当前运行_Java - Fatal编程技术网

在java中计划单线程重复运行,但如果上一次运行未完成,则跳过当前运行

在java中计划单线程重复运行,但如果上一次运行未完成,则跳过当前运行,java,Java,有时重复任务的持续时间比周期长(在我的例子中,这种情况一次可能发生数小时)。设想一个重复的任务,该任务需要7分钟运行,计划每10分钟运行一次,但有时连续几小时每次运行需要15分钟 Timer和ScheduledThreadPoolExecutor类都有一个scheduleAtFixedRate方法,通常用于此类功能。然而,两者都有一个特点,那就是“落后时努力追赶”。换句话说,如果一个计时器落后于几次执行,它将建立一个工作队列,该队列将持续工作,直到它恢复到如果没有任何任务花费的时间超过指定的时间

有时重复任务的持续时间比周期长(在我的例子中,这种情况一次可能发生数小时)。设想一个重复的任务,该任务需要7分钟运行,计划每10分钟运行一次,但有时连续几小时每次运行需要15分钟

Timer和ScheduledThreadPoolExecutor类都有一个scheduleAtFixedRate方法,通常用于此类功能。然而,两者都有一个特点,那就是“落后时努力追赶”。换句话说,如果一个计时器落后于几次执行,它将建立一个工作队列,该队列将持续工作,直到它恢复到如果没有任何任务花费的时间超过指定的时间段,将发生的运行次数。如果上一次运行未完成,我希望通过跳过当前执行来避免这种行为


我有一个解决方案,它涉及混合执行器的afterExecution方法,重新计算延迟,并用新的延迟重新安排可运行的,但我想知道是否有更简单的方法,或者这个功能是否已经存在于某个公共库中。我知道用固定的延迟而不是固定的时间来安排,但这对我来说不起作用,因为在固定的时间执行任务很重要。有比我的后执行解决方案更简单的选项吗?

我认为您希望长时间运行的任务本身不在ScheduledExecutorService中运行,而是在后台线程中运行。然后,固定速率任务将始终快速完成,因为它仅用于检查是否在后台启动实际任务(如果从上次开始仍在运行,则检查是否启动)

ScheduledExecutorService executorService=Executors.newScheduledThreadPool(1);
最终可运行的actualTask=null;
executorService.scheduleAtFixedRate(新的Runnable(){
private final executor service executor=Executors.newSingleThreadExecutor();
私人执行;
@凌驾
公开募捐{
if(lastExecution!=null&&!lastExecution.isDone()){
返回;
}
lastExecution=executor.submit(实际任务);
}
},10,10,时间单位(分钟);

做第三个类,比如叫协调员。Coordinator有一个synchronized startRunning()方法,该方法将isRunning设置为true,并在另一个线程尚未运行时返回true。还应该有一个同步的stopRunning方法,将isRunning设置为false。如果runnable已在运行,则返回true。创建该类的单个实例,并传递对所构造的所有可运行程序的引用。在runnable的run方法中,首先调用startRunning并检查返回,以验证另一个方法是否尚未运行。确保将代码放入try finally中的run()中,并从finally块中调用stopRunning。

您可以使用
scheduleWithFixedDelay
方法。这与此类似,但这一个没有错过运行的队列,而是仅在当前可运行的终止时才开始重新计数

将根据延迟参数计划重新执行Runnable的状态:

一次执行的终止与下一次执行的开始之间的延迟


@琼德里:对不起,错过了你的最后一句话。我还有一些其他的想法,不确定它们是否会更干净。@jonderry:好的,我认为我发布的最新建议很好。我清理了我的答案,您可以查看其他建议的编辑历史记录。谢谢,这看起来比我的解决方案更简洁。最简单的方法是让您的任务检查是否有其他实例已在运行,如果有,立即自拍。@hotlicks:ScheduledExecutorService实际上并没有并行运行它们。那么这里的关键要求是什么?它总是以10分钟的间隔开始,不管它是否错过了一次?如果是这样的话,你不是在谈论费率。@MarkPeters--我看不出有使用ScheduledExecutorService的要求。@HotLicks:很公平,在你的建议中,任务是如何安排的?(OP当前正在使用ScheduledExecutorService)
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
final Runnable actualTask = null;

executorService.scheduleAtFixedRate(new Runnable() {
    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    private Future<?> lastExecution;
    @Override
    public void run() {
        if (lastExecution != null && !lastExecution.isDone()) {
            return;
        }
        lastExecution = executor.submit(actualTask);
    }
}, 10, 10, TimeUnit.MINUTES);