Java可完成的未来-最好是未来的循环还是循环的未来?

Java可完成的未来-最好是未来的循环还是循环的未来?,java,asynchronous,Java,Asynchronous,我需要为不同的数据运行一个方法数百次,在该方法的不同点等待来自DB的数据或来自web调用的响应。异步运行此操作似乎是有意义的,以便在等待时间内进行处理,但是我必须等待所有运行返回的结果,然后才能继续,我的问题是,这两者之间有什么区别: 创建一个可完成的未来,并在其中运行循环。然后,在继续前进之前,确保可完成的未来已经完成。 或 创建一个循环,每个循环都有一个方法调用,然后使用allOf等待最后一个方法调用完成 谢谢在CompletableFututre中运行for循环不是一个好主意,因为for循

我需要为不同的数据运行一个方法数百次,在该方法的不同点等待来自DB的数据或来自web调用的响应。异步运行此操作似乎是有意义的,以便在等待时间内进行处理,但是我必须等待所有运行返回的结果,然后才能继续,我的问题是,这两者之间有什么区别:

  • 创建一个可完成的未来,并在其中运行循环。然后,在继续前进之前,确保可完成的未来已经完成。 或
  • 创建一个循环,每个循环都有一个方法调用,然后使用allOf等待最后一个方法调用完成

  • 谢谢

    CompletableFututre
    中运行for循环不是一个好主意,因为for循环将同步执行。让多个
    CompletableFuture
    多次调用同一个方法是一个更好的主意,但是您应该确保所有阻塞的方法都是异步执行的

    List<CompletableFuture> futures = Arrays.asList("1", "2", "3")
            .stream()
            .map(a -> CompletableFuture.supplyAsync(() -> method1(),
                    executorService))
            .map(a -> a.thenCompose(b -> CompletableFuture.supplyAsync(() -> dbcall(b),
                    dbExecutorService)))
            .collect(Collectors.toList());
    
    List futures=Arrays.asList(“1”、“2”、“3”)
    .stream()
    .map(a->CompletableFuture.SupplySync(()->method1(),
    (服务)
    .map(a->a.thenCompose(b->CompletableFuture.SupplySync(()->dbcall(b)),
    数据库(服务)))
    .collect(Collectors.toList());
    
    这样,
    method1
    dbcall
    在不同的
    ExecutorService
    上执行,并且在
    dbExecutorService
    中阻止对DB的调用不会导致
    ExecutorService

    项目中的线程耗尽 当技术进入Java时,这项工作将变得更简单

    此项目正在向Java并发工具箱添加虚拟线程()。许多正在运行的虚拟线程可以映射为在平台/内核线程之上运行。当一个虚拟线程阻塞时,它被“停驻”,另一个虚拟线程被分配在平台/内核线程上执行。虚拟线程之间的切换非常快,这使得线程阻塞对性能的影响非常便宜

    虚拟线程在内存使用方面也非常便宜。尽管平台/内核线程被分配了相当大的堆栈大小,不管需要什么,但虚拟线程有一个堆栈,它可以根据需要扩展…当不再需要时会收缩

    虚拟线程承诺消除使用线程池的风险。每个线程都有自己的值

    基于早期访问Java 17的实验构建是。项目团队正在征求反馈意见

    AutoCloseable
    在绝缘线束中,接口变为。所以我们可以使用语法。只有在所有提交的任务完成/失败/取消后,控制流才会离开
    try
    块。离开
    try
    块时,executor服务将自动关闭

    不需要
    CompletableFuture
    您可以简单地启动许多虚拟线程,甚至数百万个,然后让它们运行。对蒸发的许多方法的大多数需求。有关更多信息,请参阅Oracle的Ron Pressler最近的演示和访谈

    我们可以简单地剥离虚拟线程上的所有任务,沿途收集对象。然后简单地等待所有这些任务完成

    示例代码 建立一个
    ExecutorService
    实例。向该执行者服务提交您的
    可调用任务。捕获返回的
    未来
    对象以跟踪成功完成

    int countTasks=1_000;//要拆分为线程的任务数。
    List>futures=new ArrayList(countTasks);
    试一试(
    ExecutorService ExecutorService=Executors.newVirtualReadExecutor();
    )
    {
    for(int i=0;iFuture=executorService.submit(()->{
    //每个线程中要完成的工作。
    YourResultClass yourResultObject=;
    将结果返回到对象;
    } );
    期货。添加(期货);
    }
    }
    //在这一点上,控制块的流动将停止,直到所有提交的任务完成/失败/取消。
    //在此之后,executor服务将自动关闭。
    
    工作完成后,我们可以对收集的
    Future
    对象进行示例以验证结果

    //报告所有未来,以及千项任务的所有结果。
    对于(未来未来:未来)
    {
    尝试
    {
    System.out.println(
    “future.isDone():”+(future.isDone()+”| future.iscompletednormaly():“+future.iscompletednormaly()+”| future.isCancelled():“+future.isCancelled()+”|结果:“+future.get().toString())
    );
    }
    捕捉(中断异常e)
    {
    e、 printStackTrace();
    }
    捕获(执行例外)
    {
    e、 printStackTrace();
    }
    }
    
    示例应用程序 这是一个完整的应用程序。当然不是我在制作中会做的,但我希望这会是一次像样的演示

    这段代码衍生出一千个任务。每个任务都会打一个REST电话,要求Wikipedia提供一个随机页面。然后,该页面的内容被写入一个文件。我们收集在向executor服务提交
    Callable
    任务时返回的对象,并在工作完成后检查这些对象

    我配置了一个内存中的数据库,但您也可以将该数据库存储起来

    为了简单起见,我将我的
    WikipediaPage
    类定义为
    记录。这是编写一个类的简单方法,该类的主要目的是不可变和透明地传输数据。编译器隐式地创建构造函数、getter、
    equals
    &
    hashCode
    toString
    。不