java - 在执行器中从自身内部取消任务或超时后从外部取消

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

最佳答案

Future.get 返回时,您的第一个任务已完成,但可能会使用相同的 Runnable 安排另一个任务。对第一个 Future 调用 cancel 不起作用,因为它代表第一个(已完成)任务,而不是新的计划任务。请记住,每次调用 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 ,这就是您的问题所在。只要不满足条件并且任务没有取消,就不需要重新安排;循环将继续运行。

如果任务较多,只需增加执行器的线程数即可。这可能感觉像资源消耗,但 sleep 线程不会消耗太多资源,并且 ScheduledExecutor 也会在任务执行之间保持一个 Thread sleep 。您甚至可以在不重新安排任务时节省一些操作。

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

关于java - 在执行器中从自身内部取消任务或超时后从外部取消,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24005755/

相关文章:

java - 监控线程执行

Java newFixedThreadpool 使前 n 个线程保持挂起状态

java - SQL 服务器,HQL : How to compare SQL server datetime column field to date

java - java中将二维数组写入文件

java - FindBugs:使用 JPA 元模型时如何避免 "Unwritten public field"警告?

java - 构造函数中非线程安全集合的突变是否需要同步?

java - ThreadLocal 上的操作是否必须同步?

django - get_or_create() 线程安全吗

java - ServerSocket.accept 给了我多个连接,尽管我只连接一次

java - Websphere Application Server 6.1数据源上的UnsatisfiedLinkError