【问题标题】:How to get ExecutorService or CompletionService to finish without asking for values of Futures?如何让 ExecutorService 或 CompletionService 完成而不询问 Futures 的值?
【发布时间】:2015-06-29 14:34:37
【问题描述】:

我们有一些工作要在一个线程中完成,该线程将在服务器上运行,用于使用 Spring Boot 的 Web 应用程序。

我们想要发生的是: 1) 工作作为我们的自定义 Runnable 对象提交 2) 轮到它时工作完成(这是一个数据库操作,我们不需要任何返回值,除非在 run() 无异常完成时可能返回“Success”)

然而,在我们的 JUnit 测试中,似乎所有提交给 ExecutorService 或 CompletionService 的任务都会在主线程完成后消失,除非我们每次添加新任务时都调用 take()(因为它会阻塞直到任务完成完成,这使得任务按顺序运行,这违背了目的)或者如果我们维护一个期货列表并调用一个方法来遍历列表并获取()每个特征的值。

我们认为后一种选择并不理想,因为作为服务器应用程序,我们将不断收到来自不同用户的请求,并且不知道如何检测何时应该清除期货列表。

为什么线程会默默消失,有什么方法可以解决这个问题?

【问题讨论】:

  • 这就是 JUnit 测试的默认运行程序的工作方式。它在执行完@Test 方法后终止JVM。
  • 您可以拨打 awaitTermination stackoverflow.com/questions/1250643/…
  • 哦,我明白了——所以在 JUnit 之外,线程将完成(假设没有例外),而不需要期货。有趣,谢谢!

标签: java concurrency executorservice


【解决方案1】:

不要异步运行代码:直接测试Runnable

@Test
public void test() {
    Runnable r = <your runnable>;
    r.run();
    // various assertions
}

测试您选择的ExecutorService 是否能正常工作是毫无意义的 - 您可以假设。

如果您想断言您的应用程序行为正确,请使用功能测试;即,使用超音速数据源启动一个容器(例如使用@SpringJUnit4ClassRunner),点击spring boot 端点,然后断言对数据库的影响。

如果您为您的服务使用 spring boot 的 @Async 注解,您甚至可以提供使用 SynchronousTaskExecutor 的配置,这样您就不必在进行断言之前暂停测试。

【讨论】:

    【解决方案2】:

    测试异步代码的一个好方法是阻塞主测试线程并在回调中使用ConcurrentUnit 之类的东西执行断言。下面是一个使用 CompletableFuture 的 whenComplete 回调的示例:

    Waiter waiter = new Waiter();
    
    CompletableFuture<Connection> future = someService.connect();
    future.whenComplete((connection, failure) -> {
      // Called from some other thread
      waiter.assertNotNull(connection);
      waiter.assertNull(failure);
      waiter.resume();
    });
    
    // Block the main test thread
    waiter.await();
    

    如果回调线程中的任何一个断言失败,则测试将按预期失败。主测试线程将在完成测试之前等待resume 调用。

    【讨论】:

      猜你喜欢
      • 2011-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-17
      • 1970-01-01
      • 2015-11-26
      相关资源
      最近更新 更多