在Executors中从内部取消任务或在超时后从外部取消

时间:2014-06-03 01:26:17

标签: java multithreading executorservice scheduledexecutorservice

好的,所以我花了一些时间环顾四周但却找不到明确的解决方案。我之前发布了一个单独的问题,但这个问题有点不同。

问题:我想定期轮询一个条件。如果该条件仍为假,则再次重新安排。如果为true,则停止计划。但我也想等待一段确定的时间。这是我写的

 final ScheduledExecutorService service = Executors.newScheduledThreadPool(1);

  final Future<?> future = service.schedule(new Runnable() {
        @Override
        public void run() {
            if (conditionFalse()) {
                System.out.println("its false. Rescheduling");
                service.schedule(this, 2, TimeUnit.SECONDS);
            } else {
                System.out.println("true. Exiting");
            }
        }
    }, 2, TimeUnit.SECONDS);

   //Wait only for 5 seconds 
   future.get(5, TimeUnit.SECONDS); // does not work
   //does not work either
     service.schedule(new Runnable() {
        @Override
        public void run() {
            future.cancel(true);
        }
    }, 5, TimeUnit.SECONDS);

这会一直重新安排,直到满足条件。为什么它不起作用的任何建议?我如何只等待5秒然后停止执行任务?

1 个答案:

答案 0 :(得分:1)

Future.get返回时,您的第一个任务已完成,但可能使用相同的Runnable安排了其他任务。在第一个cancel上调用Future无效,因为它代表第一个(已完成)任务,但不代表新的计划任务。请注意,schedule的每次调用都会返回一个新的Future

最后还不清楚你为什么要把这个任务变得如此复杂。后台线程的一大优势是它们可以在不影响整个程序执行的情况下执行阻塞操作。因此,如果您想每两秒重新检查一个条件,只需创建一个后台任务,实现每两秒检查一次的逻辑。等待两秒钟将阻止该线程,但没关系,它是一个后台线程

ExecutorService service=Executors.newFixedThreadPool(1);
Future<?> f=service.submit(new Runnable() {
  public void run() {
    try {
      while(conditionFalse()) {
        System.out.println("it’s false, will wait");
        Thread.sleep(TimeUnit.SECONDS.toMillis(2));
      }
      System.out.println("true. exiting.");
    } catch(InterruptedException ex) {
      System.out.println("interrupted. exiting.");
    }
  }
});
try {
  try {
    f.get(5, TimeUnit.SECONDS);
    System.out.println("conditions met even before trying to cancel");
  } catch(TimeoutException ex) {
    System.out.println("canceling");
    System.out.println(f.cancel(true)?
      "canceled before conditions met": "conditions met before canceled");
  }
} catch(InterruptedException | ExecutionException ex) {
  throw new AssertionError(ex);
}

取消任务将立即结束sleep,这就是您的问题所在。只要条件不符合且任务没有取消,就不需要重新安排任何事情;循环将继续运行。

如果您有更多任务,只需提高执行程序的线程数。它可能感觉像资源消耗,但是睡眠线程不会消耗太多资源,ScheduledExecutor也会在任务执行之间保持Thread休眠。在没有重新安排任务时,你甚至可以保存一些操作。

重要的是代码是否清晰易懂,我认为,简单循环胜过(甚至不工作)重新安排代码。