【问题标题】:Do I need to control the execution of these two threads with the main threads?我需要用主线程控制这两个线程的执行吗?
【发布时间】:2018-11-03 19:37:09
【问题描述】:
void process(String question){

                    Callable<ResponseList> callable1 = () -> this.stsCompute question);
                    Future<ResponseList>task1 = executorService.submit(callable1);

                    Callable<ResponseList> callable2 = () -> this.dssmCompute(question);
                    Future<ResponseList>task2 = executorService.submit(callable2);

                    try{
                        ResponseList stsResponse = task1.get();
                        ResponseList dssmResponse = task2.get();
                    }catch (Exception e){
                        e.printStackTrace();
                    }

                    // Do I need to wait until the first 2 threads complete?
                    processResponse(stsResponse, dssmResponse);
}

在这个“进程”方法中,我有两个额外的线程“callable1”和“callable2”同时执行。我想确保只有当这两个任务完成时,主线程'processResponse()'中的方法才能开始执行。

在这种情况下,我是否需要添加任何额外的控件来确保执行的顺序,它已经足够了吗?如果没有,如何实现这种控制?

【问题讨论】:

  • 测试时会发生什么? Future.get() 的 javadoc 是怎么说的?
  • “get() 文档说,如果需要,等待计算完成,然后检索其结果。”这对 3 个线程之间的时间关系没有太大帮助。
  • 嗯,是的,确实如此。它的字面意思是:等待 [...] 计算完成。并且您要确保只有当这两个任务完成后,主线程'processResponse()' 中的方法才能开始执行。鉴于您在调用 processResponse() 之前在两个期货上调用 get(),并且 get() 一直等到任务完成,所以您所做的确实确保 processResponse() 之前不会开始执行两项任务都完成了。
  • 我同意JB Nizet,但请注意,当task1抛出异常并且task2仍在执行时,可以执行processResponse。
  • 感谢 JB Nizet 和 Donat。太好了。

标签: java executorservice callable


【解决方案1】:

您应该使用 ExecutorService.invokeAll,它会在完成时返回期货列表。此外,我会使用更短的语法,比如

 List<Future> futures = executorService.invokeAll(Arrays.asList(()->dssmCompute(), ()->dssmCompute()));

【讨论】:

  • 在返回的List中,如何知道哪个future是由哪个方法产生的?它们是否与数组索引对齐?
  • API 说 Returns:代表任务的 Futures 列表,其顺序与给定任务列表的迭代器生成的顺序相同。
【解决方案2】:

对于 Java8+,我建议使用 Completable Futures。它完全支持您尝试实现的用例。

可完成的期货:Java 8

示例算法如下所示:

var cf = CompletableFuture.supplyAsync(() -> processQuestion()).runAsync(() -> processResponse)

注意: var 是 java 10+ 中支持的 typeInference

另外,关于 Completable Futures 的例子很多

【讨论】:

  • " 因为方法 'process' 必须被重复调用,这是在 Java 中实现并发的正常方法吗?是否会因为每次调用 'process' 都会产生大量开销导致两个future对象的创建和销毁?我最初的目的是为了加快我的程序,我希望它不会因为无数的线程的创建和销毁而减慢。”
  • 嗨,Anvesh,我的问题呢?
  • @User697911 您可以使用 Executor 服务传递 CompletableFutures 以确保创建的线程不会超过您指定的数量。也可以考虑使用 allOf() 例如:baeldung.com/java-completablefuture
  • 我定义了“private ExecutorService executorService = Executors.newFixedThreadPool(2);”作为“定义流程”的类的实例变量。所以只调用了一个'ExecutorService',但是'Callable'被重复创建和销毁,因为'process'被重复调用。
  • @user697911 听起来不错。你可以使用更多的 Completable futures 而不是 callable,然后使用 allOf()。此外,如果您使用的那些可调用 Future 不受任何 http 调用或 io 操作的限制,并且仅用于在应用程序内部进行处理。无需担心线程数,它们在完成过程中应该非常快。我不太确定您正在创建的每个可调用对象的用例。就我个人而言,我以异步方式使用了很多可完成的期货,并且能够处理我的应用程序的峰值负载。
猜你喜欢
  • 1970-01-01
  • 2023-03-30
  • 2014-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多