首页 > 编程语言 >java 用CompletableFuture来实现多线程查询和结果合并

java 用CompletableFuture来实现多线程查询和结果合并

时间:2023-08-13 23:32:49浏览次数:40  
标签:java get 方法 查询 CompletableFuture join 多线程 异常

多线程查询结果合并

使用CompletableFuture来实现多线程查询和结果合并。CompletableFuture提供了一种方便的方式来协调异步任务并处理其结果。下面是一个使用CompletableFuture的示例:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

public class MultiThreadQueryExample {

    public static void main(String[] args) {
        // 模拟要查询的数据
        List<String> data = new ArrayList<>();
        for (int i = 1; i <= 100; i++) {
            data.add("Data " + i);
        }

        // 创建CompletableFuture列表,用于存储每个查询的结果
        List<CompletableFuture<List<String>>> futures = new ArrayList<>();

        // 每个CompletableFuture负责查询一部分数据
        int batchSize = 20;
        for (int i = 0; i < data.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, data.size());
            List<String> subList = data.subList(i, endIndex);
            CompletableFuture<List<String>> future = CompletableFuture.supplyAsync(() -> performQuery(subList));
            futures.add(future);
        }

        // 使用CompletableFuture的allOf方法等待所有查询完成
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));

        // 当所有查询完成时,对所有结果进行合并
        CompletableFuture<List<String>> mergedResult = allFutures.thenApply(v ->
                futures.stream()
                        .map(CompletableFuture::join)
                        .flatMap(List::stream)
                        .collect(Collectors.toList())
        );

        // 阻塞等待合并结果
        List<String> result = mergedResult.join();

        // 输出合并后的结果
        System.out.println("Merged Result:");
        for (String r : result) {
            System.out.println(r);
        }
    }

    private static List<String> performQuery(List<String> data) {
        // 在这里进行查询操作,返回查询结果

        // 模拟查询耗时
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 返回查询结果
        List<String> result = new ArrayList<>();
        for (String item : data) {
            result.add("Result for " + item);
        }
        return result;
    }
}

在这个示例中,我们使用CompletableFuture.supplyAsync()方法将查询任务提交给线程池执行异步查询操作,并返回一个CompletableFuture对象表示查询的结果。所有的CompletableFuture对象存储在futures列表中。

然后,我们使用CompletableFuture.allOf()方法等待所有查询任务完成。当所有任务都完成时,我们使用thenApply()方法对所有结果进行合并操作,最终得到一个合并后的CompletableFuture<List<String>>对象。

通过调用join()方法,我们可以阻塞等待合并结果的完成,并获取最终的查询结果。

请注意,CompletableFuture还提供了其他一些方法,如thenCompose()thenCombine()等,可以进一步实现异步任务的流水线处理和组合操作,以满足不同的业务需求。


future.join()与future.get()的区别

future.join()future.get() 都可以用于获取 CompletableFuture 的结果,但在具体的使用上有一些差异。

  1. 异常处理:join() 方法在遇到异常时会将其包装在 CompletionException 中直接抛出;而 get() 方法会抛出 InterruptedException(需要处理线程中断)和 ExecutionException(需要处理任务执行过程中发生的异常)。因此,在使用时需要根据具体情况选择合适的异常处理方式。
  2. 受检异常:get() 方法声明了抛出 InterruptedExceptionExecutionException 这两个受检异常,因此在使用 get() 方法时必须显式地处理这两种异常,或者将它们往上层抛出。相比之下,join() 方法没有声明受检异常,所以不需要在代码中强制处理。
  3. 线程中断:get() 方法会抛出 InterruptedException,这意味着在调用 get() 时,如果当前线程被中断,就会抛出该异常。这要求在使用 get() 方法时必须处理线程中断的情况。而 join() 方法并不抛出 InterruptedException,所以在调用 join() 时不会对线程中断状态进行检查和处理。
  4. 返回值和异常封装:get() 方法返回的是 Future 的结果对象,通过调用 get() 方法可以获取这个结果,或者通过 isDone() 方法判断是否完成。而 join() 方法直接返回结果值,并且如果遇到异常,会将异常包装在 CompletionException 中抛出。

总结来说,join() 方法更加简洁,不需要显式处理受检异常和线程中断,但对于异常处理,其抛出的异常类型相对固定,无法区分具体的异常类型。而 get() 方法需要显式处理受检异常和线程中断,但可以更细粒度地对不同类型的异常进行处理。


标签:java,get,方法,查询,CompletableFuture,join,多线程,异常
From: https://blog.51cto.com/u_16176998/7070585

相关文章

  • Java知识补漏
    Java知识补漏内存溢出在强制类型转换时,有可能产生内存溢出现象,如以下代码publicclassText01{publicstaticvoidmain(String[]args){inti=128;bytej=(byte)i;System.out.println(j);}}变量数字类型变量可以用下划线分割,不......
  • 【==是判断相等吗?---错辣】C++和JAVA中判断字符串值相等的区别
    参考文章:这里;这里;这里先上结论C++中的string类型可以使用==和!=来判断两个字符串的值是否相等;而JAVA不行,JAVA中==和!=是用来判断两个字符串的地址是否相同(或者说是对象是否相同,即是否为同一个对象)。C++中string#include<iostream>#include<string>usingnamespacestd;intmai......
  • java基础02
    数据类型扩展进制,二进制以0b开头,八进制以0开头,十六进制以0x(x必须为小写)开头,如:publicclasshello{publicstaticvoidmain(String[]args){inti=0b10;//二进制inti2=10;//十进制inti3=010;//八进制inti4=0x10;//十......
  • Java入门学习——day3(基础语法)
    使用变量的几个注意事项变量要先声明才能使用。这里的age没有声明,会标红,鼠标放在标红的age上出现了Cannotresolvesymbol'age',运行会报错!改正:变量是什么类型,就应该用来装什么类型的数据,否则报错。本来age是int类型,但是我们给了一个double类型。改正:变量是从定义开始到“}”......
  • 《深入理解Java虚拟机》读书笔记:内存分配策略
    Java技术体系中所提倡的自动内存管理最终可以归结为自动化地解决了两个问题:给对象分配内存以及回收分配给对象的内存。关于回收内存这一点,我们已经使用了大量篇幅去介绍虚拟机中的垃圾收集器体系以及运作原理,现在我们再一起来探讨一下给对象分配内存的那点事儿。对象的内......
  • Java语法
    第一个Java程序下面看一个简单的Java程序,它将输出字符串 HelloWorld实例publicclassHelloWorld{/*第一个Java程序*它将输出字符串HelloWorld*/publicstaticvoidmain(String[]args){System.out.println("HelloWorld");//输出HelloWorld}}运行......
  • Java判断word文档的重复,达到word文档的整理、整合效果代码实现
    在Java中,你可以使用ApachePOI库来操作Word文档并实现判断文档的重复。以下是一种实现思路:导入ApachePOI库:首先,你需要在Java项目中导入ApachePOI库,以便能够使用它的功能。你可以在项目的构建文件(如Maven或Gradle)中添加相应的依赖项。读取Word文档内容:使用ApachePOI库的XWPFDocum......
  • Java中Integer数据类型详细用法
    Java中的Integer类在对象中包装了一个基本类型int的值。以下是关于Integer类的详细用法和相关代码:1.构造方法:Integer(intvalue):构造一个新分配的Integer对象,它表示指定的int值。Integer(Strings):构造一个新分配的Integer对象,它表示String参数所指示的int值。javaCopycodeI......
  • Java-重写
    Java-重写重写:就是父亲给儿子的儿子不想要,他要改一下定义:子类对父类给的方法不满意,对父类方法进行重新定义。要求:子类方法的声明必须和父类中的方法完全一样。比如:父类李渊packagecom.wq.bao;/***@authorWangQi*@date2020/4/222:46*/publicclassLiYuan{......
  • JavaScript学习笔记
    JavaScript1JavaScript输出JavaScript能够以不同方式"显示"数据:使用window.alert()写入警告框使用document.write()写入HTML输出使用innerHTML写入HTML元素使用console.log()写入浏览器控制台1.1使用innerHTML如需访问HTML元素,JavaScript可使用doc......