有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java线程池/未来正确的方法?

我有一个WebMvc rest api。我的rest方法之一是“长时间运行的任务”。我的初始实现花费了100秒来完成测试数据

我的第二种方法是将测试数据分成多个页面,并使用线程池。在我的服务层中,我有private final ExecutorService executor = Executors.newFixedThreadPool(8);,我用List<Future<Page>> results = this.executor.invokeAll(pages);提交给它,这使它下降到45秒

问题是等待所有的页面。我确实需要为最终json响应准备好页面,因此我正在做:

        List<Future<Page>> results = this.executor.invokeAll(pages);

        for (Future<Page> result : results)
            result.get();

如果我这样做,我想我真的不在乎他们完成的顺序,因为他们在原始页面列表中的顺序是正确的

但是get()是一个阻塞调用。这对webmvc rest api有影响吗


共 (1) 个答案

  1. # 1 楼答案

    我可以{a1}告诉你{}返回一个期货列表,其顺序与传递的可调用项相同,即传递的{}列表中的第三个{}是{}期货列表中第三个{}的来源

    Returns: a list of Futures representing the tasks, in the same sequential order as produced by the iterator for the given task list, each of which has completed

    到目前为止,只要你是好的,你可以在之后访问这些它们中的所有将返回trueon Future::isDone,没有办法使用这种方法访问中间结果

    您可以使用CompletableFuture::supplyAsync(Supplier<T>, Executor)的多个调用来获取List<CompletableFuture<T>>,然后使用CompletableFuture::thenAccept(Consumer<T>)在等待其他结果的同时在完成时执行操作

    为简洁起见,使用String而不是Page的最小样本:

    Random random = new Random();
    // simulate irregular delay
    List<Callable<String>> pages = List.of(
        () -> { Thread.sleep(random .nextInt(3000)+2000); return "one";},
        () -> { Thread.sleep(random .nextInt(3000)+2000); return "two";},
        () -> { Thread.sleep(random .nextInt(3000)+2000); return "three";},
        () -> { Thread.sleep(random .nextInt(3000)+2000); return "four";},
        () -> { Thread.sleep(random .nextInt(3000)+2000); return "five";}
    );
    
    ExecutorService executor = Executors.newFixedThreadPool(8);
    List<CompletableFuture<String>> results = pages.stream()
        .map(callable -> CompletableFuture.supplyAsync(
            // this should be wrapped into a method instead
            () -> { try {return callable.call();} catch (Exception ignore) {} return null; },
            executor))
        .collect(Collectors.toList());
    
    // clumsy index print to demonstrate the immediate results
    for (int i=0; i<results.size(); i++) {
        int index = i;
        results.get(i).thenAccept(page -> System.out.println("Finished (" + index + ") : " + page));
    }
    

    不幸的是,创建者似乎希望在设计CompatibleFuture时避免使用检查异常,因此它与Callable<T>不兼容