3

我正在使用 Spring 的 TaskScheduler 来安排定期任务。

ScheduledFuture scheduleAtFixedRate(Runnable task, long period);

我知道我可以在 ScheduledFuture 上调用 cancel() 来停止执行重复任务。但是我想根据任务执行的结果取消重复的计划任务,并且不知道如何最好地做到这一点。

ScheduledFuture 是否允许我访问每个执行任务的结果?或者我是否需要某种任务监听器来保持对这个 ScheduledFuture 的引用,并以这种方式取消它?或者是其他东西?

4

3 回答 3

3

好的,看起来这是可能的,但可能有更好的方法。

由于重复作业只需要一个 Runnable(返回类型为 void),因此无法返回任务的结果。因此,停止重复任务的唯一方法是使任务执行副作用,例如将停止消息添加到队列中。然后一个单独的线程需要监视这个队列,一旦它看到消息就可以取消作业。

非常混乱和复杂。

更好的选择是创建一个正常的(一次性)计划任务。然后任务本身可以决定是否需要调度另一个任务,并且可以自己调度下一个任务。

于 2013-02-28T22:55:47.530 回答
2

保留一个句柄或原来的固定费率ScheduledFuture,然后当您想要取消它的条件出现时,安排一个执行取消的新任务。

您也可以使用RunnableScheduledFuture.

ScheduledExecutorService文档

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html

 import static java.util.concurrent.TimeUnit.*;
 class BeeperControl {
   private final ScheduledExecutorService scheduler =
     Executors.newScheduledThreadPool(1);

   public void beepForAnHour() {
     final Runnable beeper = new Runnable() {
       public void run() { System.out.println("beep"); }
     };
     final ScheduledFuture<?> beeperHandle =
       scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
     scheduler.schedule(new Runnable() {
       public void run() { beeperHandle.cancel(true); }
     }, 60 * 60, SECONDS);
   }
 }
于 2016-05-06T22:27:17.017 回答
0

这是一个修改后的蜂鸣器示例,演示了如何在每个计划任务之后做出决定。我使用了一个闩锁,这样我就可以将它包装在一个测试用例中并断言发生了正确的事情(当然是为了防止测试运行器的线程停止)。我还更改了间隔(在最初的 10 毫秒延迟后,它每 10 毫秒发出一次哔声),因此可以在一秒钟内而不是一小时内复制、粘贴和执行测试。


import org.junit.Assert;
import org.junit.Test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class BeeperTest {
    class BeeperControl {
        private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, (runnable) -> {
            Thread thread = new Thread(runnable);
            thread.setName("MyAwesomeBeeperTestThread");
            thread.setDaemon(true);
            return thread;
        });

        public void beepTheNumberOfTimesIWant(CountDownLatch latch) {
            long initialDelay = 10;
            long frequency = 10;
            TimeUnit unit = TimeUnit.MILLISECONDS;
            final int numberOfTimesToBeep = 5;
            AtomicInteger numberOfTimesIveBeeped = new AtomicInteger(0);
            final ScheduledFuture[] beeperHandle = new ScheduledFuture[1];
            beeperHandle[0] = scheduler.scheduleAtFixedRate(() -> {
                    if (numberOfTimesToBeep == numberOfTimesIveBeeped.get()) {
                        System.out.println("Let's get this done!");
                        latch.countDown();
                        beeperHandle[0].cancel(false);
                    }
                    else {
                        System.out.println("beep");
                        numberOfTimesIveBeeped.incrementAndGet();
                    }
                }, initialDelay, frequency, unit);
        }
    }

    @Test
    public void beepPlease() throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(1);
        BeeperControl control = new BeeperControl();
        control.beepTheNumberOfTimesIWant(latch);
        boolean completed = latch.await(1, TimeUnit.SECONDS);
        Assert.assertTrue("Beeper should be able to finish beeping" +
            "within allotted await time.", completed);
    }
}
于 2019-04-11T19:57:10.927 回答