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