从ScheduledExecutorService中运行的任务本身中停止定期任务

在ScheduledExecutorService中运行时,是否有一种很好的方法可以阻止任务内部重复任务?

可以说,我有以下任务:

Future f = scheduledExecutor.scheduleAtFixedRate(new Runnable() { int count = 0; public void run() { System.out.println(count++); if (count == 10) { // ??? cancel self } } }, 1, 1, TimeUnit.SECONDS); 

从外面看,很容易通过f.cancel()取消,但是如何在指定的地方停止重复? (通过AtomicReference传递Future是不安全的,因为当scheduleAtFixedRate返回f迟到并且变量设置得太晚时有一个潜在的窗口,并且任务本身可能已经运行,在引用中看到null。)

当重复任务抛出exception或错误时,它将被放置在Future中,并且不会再次重复该任务。 您可以抛出您选择的RuntimeException或Error。

您可以使用命名类,而不是使用匿名内部类,该类可以为您在安排任务时从Executor获取的Future对象具有属性。

 abstract class FutureRunnable implements Runnable { private Future future; /* Getter and Setter for future */ } 

当您安排任务时,您可以将Future传递给Runnable

 FutureRunnable runnable = new FutureRunnable() { public void run() { if (/* abort condition */) getFuture().cancel(false); } }; Future future = executor.scheduleAtFixedRate(runnable, ...); runnable.setFuture(future); 

也许您必须确保在设置Future之前不执行任务,否则您将获得NullPointerException

看起来好的设计让Runnable知道它正在运行的执行器的任何信息,或者如果达到10不是错误状态则抛出错误是一个hack。

你可以在调度和执行之外循环到10吗? 这可能需要使用非调度执行程序,因为您自己手动调度它们。

这是另一种方式,即使是线程安全;

  final Future[] f = {null}; f[0]= scheduledExecutor.scheduleAtFixedRate(new Runnable() { int count = 0; public void run() { System.out.println(count++); if (count == 10) { Future future; while(null==(future = f[0])) Thread.yield();//prevent exceptionally bad thread scheduling future.cancel(false); return; //cancel self } } }, 1, 1, TimeUnit.SECONDS); 

刚看到这个…因为我想做同样的事情……这是我的解决方案,我怀疑这是线程安全的。

首先为Future创建一个容器:

 public static class Cancel { private ScheduledFuture future; public synchronized void setFuture(ScheduledFuture future) { this.future = future; } public synchronized void stop() { LOG.debug("cancelling {}", future); future.cancel(false); } } 

然后是未来的代码:

  final Cancel controller = new Cancel(); synchronized (controller) { ScheduledFuture future = scheduler.scheduleWithFixedDelay(() -> { if ( 

因此,请注意在创建未来并在控制器上设置了未来之前,停止将不会被调用。

请记住,Runnable是一个非同类的内部类,它将完全在另一个线程中运行。