Java:从 scheduleAtFixedRate 获取 future 的方法

标签 java multithreading

考虑以下代码:

public static void main(String ... args) throws InterruptedException {
  ScheduledExecutorService threadsPool = Executors.newSingleThreadScheduledExecutor();
  Future<?> f = threadsPool.scheduleAtFixedRate(() -> {
    try {
      Thread.sleep(1);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }, 0, 2, TimeUnit.SECONDS);

  Thread.sleep(5000);
  threadsPool.shutdown();
  System.out.println(threadsPool.awaitTermination(1, TimeUnit.SECONDS));
  try {
    f.get();
  } catch (Exception e) {
    e.printStackTrace();
  }
}

注意邪恶线程的 hibernate 时间:1ms。这保证了关闭将在线程池等待下一次迭代并且邪恶线程未运行时发生。
这会导致 get() 方法出现 CancellationException:如果我理解正确,ScheduledExecutorService 在调用 shutdown() 时会取消任何未决任务,因此这种行为是有道理的。

接下来我将邪恶线程的 hibernate 时间从1更改为1999。这保证了关闭将在邪恶线程 hibernate 期间。
这会导致永远等待 get() 方法。

我的下一个问题是为什么会发生这种行为?调用 shutdown 将优雅地关闭服务。事实上,邪恶的线程完成了迭代,并没有再次启动。
但是为什么get()方法没有返回呢?我是否误解了 ScheduledFuture 的 get() 方法?
我认为只要邪恶线程结束,池关闭,get() 方法就应该返回 null。

最佳答案

如果 future 没有完成,那么 future.cancel() 方法可能被 shutdown 方法调用(或者执行者以某种方式取消了 future)。 这是请求执行程序关闭的预期行为,因为它不会等待任务完成。

如果 future 在完成之前被取消,则抛出 CancellationException 是预期的行为。否则它会等待以太币让任务返回。

在这种情况下,由于您使用 ScheduledExecutorService,因此在这种情况下您可以使用 ScheduledFuture 而不是 Future 来获取更多信息。 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledFuture.html 这将允许您访问 Delayed 接口(interface)提供的 getDelay 方法。 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Delayed.html

如果您还检查方法 scheduleAtFixedRate 的源代码,您会发现它实际上创建了一个 ScheduledFutureTask。请参阅下面的代码。 (从源代码复制。)

/**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     * @throws IllegalArgumentException   {@inheritDoc}
     */
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        if (period <= 0)
            throw new IllegalArgumentException();
        ScheduledFutureTask<Void> sft =
            new ScheduledFutureTask<Void>(command,
                                          null,
                                          triggerTime(initialDelay, unit),
                                          unit.toNanos(period));
        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
        sft.outerTask = t;
        delayedExecute(t);
        return t;
    }

ScheduledFutureTaskrun 方法会在它完成后立即自动重新执行它。 (查看源代码的最后一行)。

 /**
         * Overrides FutureTask version so as to reset/requeue if periodic.
         */
        public void run() {
            boolean periodic = isPeriodic();
            if (!canRunInCurrentRunState(periodic))
                cancel(false);
            else if (!periodic)
                ScheduledFutureTask.super.run();
            else if (ScheduledFutureTask.super.runAndReset()) {
                setNextRunTime();
                reExecutePeriodic(outerTask);
            }
        }

outerTaskthis 所以它实际上是 ScheduledFutureTask 本身。所以它永远不会完整。由于这个原因,您实际上永远无法得到结果。

关于Java:从 scheduleAtFixedRate 获取 future 的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33911951/

相关文章:

c - C 线程程序中的链接器错误..ld 返回 1 退出状态

c - 什么执行进程和线程生成进程

java - 使用线程池查询远程数据库

java - Weld -001409 : Ambiguous dependencies for type T with qualifiers @Default

java - 为什么此代码会生成无效的 Excel 文件?

用于有条件地删除空格的 Java 模式正则表达式

java - 通过 Tomcat Websocket 将图像缓冲为 JPG 到 HTML 5 Canvas

java - 使用连接池时的并发修改

java - 如何让volley onResponse在UnitTest线程中运行

java - 如何让这段代码继续循环,直到输入正确的学号?