1

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

问题:我想轮询定期发生的情况。如果该条件仍然为假,请再次重新安排。如果为真,则停止调度。但我也只想等待一些确定的时间。这是我写的

 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 秒然后停止任务执行?

4

1 回答 1

1

返回时,您的第一个任务Future.get已经完成,但可能使用相同的. 调用第一个没有效果,因为它代表第一个(完成的)任务,而不是新的计划任务。请记住,每次调用都会返回一个新的.RunnablecancelFuturescheduleFuture

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

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在不重新安排任务时,您甚至可以节省一些操作。

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

于 2014-06-03T17:55:35.027 回答