CompletableFuture使用详解

一、CompletableFuture的简介

CompletableFuture

  1. CompletableFuture是Java 8中新增的一个类,它实现了CompletionStage接口和Future接口。CompletionStage接口是对Future接口的扩展,提供了更多的功能和灵活性。

  2. CompletableFuture提供了一系列的方法,用于处理异步任务的结果。它可以让任务在后台线程中执行,并且可以通过回调函数来处理任务的结果。这种异步的方式可以提高程序的性能,避免阻塞主线程。

  3. 除了异步执行,CompletableFuture还提供了流式处理的能力。它的方法可以链式调用,这样可以对多个任务的结果进行处理,实现任务的串行或并行执行。这种流式处理的方式使得代码更加简洁和可读。

  4. 另外,CompletableFuture还提供了一些组合的方法,比如thenCombine()、thenCompose()、allOf()、anyOf()等。这些方法可以对多个任务的结果进行组合处理,实现更复杂的逻辑。

  5. 总的来说,CompletableFuture是Java 8中非常有用的一个特性,它提供了强大的处理异步任务结果的能力,使得Java在处理多任务的协同工作时更加顺畅便利。

二、CompletableFuture的常用Api分类

1. 创建CompletableFuture对象的静态方法:

这些方法可以创建一个CompletableFuture对象,并且可以指定任务的执行线程池。

1.1 supplyAsync

例如,CompletableFuture.supplyAsync()用于创建一个CompletableFuture对象,并在指定的线程池中执行一个有返回值的任务。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureDemo {

    public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000); // 模拟耗时操作
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Hello, CompletableFuture!";
        });

        try {
            String result = future.get();
            System.out.println(result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}
  1. 这个示例中,我们使用CompletableFuture.supplyAsync()方法创建了一个CompletableFuture对象。在这个方法的参数中,我们传入了一个Lambda表达式,用于执行异步任务。在这个Lambda表达式中,我们模拟了一个耗时操作,然后返回了一个字符串。

  2. 然后,我们使用future.get()方法来获取异步任务的结果。由于CompletableFuture.supplyAsync()方法会在后台线程中执行任务,所以我们需要使用get()方法来等待任务的完成,并获取结果。在获取结果的过程中,get()方法可能会抛出InterruptedException或ExecutionException异常,我们需要进行相应的异常处理。

  3. 小结:CompletableFuture.supplyAsync()方法可以用来创建一个CompletableFuture对象,并在后台线程中执行一个异步任务。通过get()方法可以等待任务的完成,并获取结果。这种方式可以在不阻塞主线程的情况下执行耗时操作,提高程序的性能。同时,CompletableFuture还提供了丰富的方法来处理任务的结果和异常,使得异步编程更加灵活和简便。

2. 对CompletableFuture对象进行转换和处理的方法:

这些方法可以对CompletableFuture对象进行转换、处理和组合。

2.1 thenApplyAsync

thenApplyAsync()方法可以对CompletableFuture的结果进行转换。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CompletableFutureDemo {
    public static void main(String[] args) {
        // 创建自定义线程池
        ExecutorService executor = Executors.newFixedThreadPool(5);

        // 创建CompletableFuture对象,并指定线程池
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            // 异步任务
            System.out.println("异步任务执行线程:" + Thread.currentThread().getName());
            return "Hello";
        }, executor);

        // 使用thenApply方法处理任务结果,并指定线程池
        CompletableFuture<Integer> result = future.thenApplyAsync(s -> {
            // 对任务结果进行处理
            System.out.println("任务结果处理线程:" + Thread.currentThread().getName());
            return s.length();
        }, executor);

        // 等待任务结果并打印
        try {
            System.out.println("任务结果:" + result.get());
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 关闭线程池
        executor.shutdown();
    }
}
  1. 在上面的示例中,首先创建了一个自定义线程池executor,它使用Executors.newFixedThreadPool(5)方法创建一个固定大小为5的线程池。

  2. 然后,创建了一个CompletableFuture对象future,并使用supplyAsync()方法指定了异步任务。通过thenApplyAsync()方法,对任务结果进行处理,并在thenApplyAsync()方法中指定了自定义线程池executor。

  3. 最后,使用result.get()方法等待任务结果,并打印结果。

  4. 通过自定义线程池,可以灵活地控制任务的执行方式。例如,可以根据实际情况调整线程池的大小,以提高任务的并发性能。同时,在任务执行过程中,可以通过打印线程名称来观察任务的执行线程,以及任务结果处理线程的变化。

2.2 thenAccept

thenAccept()方法可以对结果进行处理。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CompletableFutureDemo {

    public static void main(String[] args) {
        // 创建一个自定义线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        // 创建一个CompletableFuture对象
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            // 模拟耗时操作
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Hello";
        }, executorService);

        // 在CompletableFuture上应用thenAccept方法
        completableFuture.thenAccept(result -> System.out.println(result + " World"));

        // 关闭线程池
        executorService.shutdown();
    }
}
  1. 在这个示例中,我们使用CompletableFuture.supplyAsync方法创建了一个CompletableFuture对象,并传入自定义的线程池executorService作为参数。然后,我们在CompletableFuture对象上应用thenAccept方法,该方法接受一个Consumer函数,用于处理CompletableFuture的结果。在这个例子中,我们简单地打印出结果。

  2. 通过自定义线程池,我们可以灵活地控制任务的执行。在这个示例中,我们创建了一个固定大小的线程池,最多同时执行5个任务。这可以提高任务的并发性,并有效地利用系统资源。

  3. 分析:CompletableFuture是Java 8引入的一个强大的异步编程工具,它可以很方便地处理异步任务的结果。使用CompletableFuture的thenAccept方法,可以在CompletableFuture完成后执行对结果的操作。

  4. 自定义线程池可以更好地控制任务的执行,通过合理地设置线程池的大小,可以同时处理多个任务,提高并发性能。这对于处理大量耗时的任务非常有用,可以避免阻塞主线程。

  5. 然而,需要注意的是,如果不正确地使用自定义线程池,可能会导致资源浪费或性能下降。因此,在使用自定义线程池时,需要根据实际情况合理地设置线程池的大小,避免创建过多的线程。另外,需要及时关闭线程池,以释放资源。

  6. 总之,使用CompletableFuture的thenAccept方法,并结合自定义线程池,可以实现更高效的异步编程。通过合理地设置线程池大小,可以提高并发性能,并更好地利用系统资源。

2.3 thenCombine

thenCombine()方法可以组合多个CompletableFuture的结果。

import java.util.concurrent.CompletableFuture;

public class CompletableFutureDemo {
    public static void main(String[] args) {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10);
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 20);

        CompletableFuture<Integer> combinedFuture = future1.thenCombine(future2, (result1, result2) -> result1 + result2);

        combinedFuture.thenAccept(result -> System.out.println("Combined Result: " + result));
    }
}
  1. 在这个例子中,我们创建了两个CompletableFuture对象:future1和future2。每个CompletableFuture对象都返回一个整数值。

  2. 然后,我们使用thenCombine方法将这两个CompletableFuture对象组合起来。这个方法接受两个参数:第一个参数是第一个CompletableFuture对象,第二个参数是第二个CompletableFuture对象。第三个参数是一个函数,用于将两个CompletableFuture的结果进行合并。

  3. 在这个例子中,我们将两个CompletableFuture对象的结果相加。

  4. 最后,我们使用thenAccept方法来处理合并后的结果,并将其打印出来。

  5. 这个例子展示了如何使用CompletableFuture的thenCombine方法来组合两个CompletableFuture对象的结果,并对结果进行处理。

  6. 这种组合操作可以在需要同时处理多个CompletableFuture对象的情况下非常有用,以提高并发性能。

3. 对CompletableFuture对象进行异常处理的方法:

这些方法可以对CompletableFuture对象的异常进行处理。

3.1 exceptionally

exceptionally()方法可以对CompletableFuture的异常进行处理,并返回一个默认值。

import java.util.concurrent.CompletableFuture;

public class CompletableFutureDemo {
    public static void main(String[] args) {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            // 模拟一个可能抛出异常的操作
            if (Math.random() < 0.5) {
                throw new RuntimeException("Oops, something went wrong!");
            }
            return 10;
        });

        CompletableFuture<Integer> exceptionallyFuture = future.exceptionally(ex -> {
            System.out.println("Exception occurred: " + ex.getMessage());
            return -1;
        });

        exceptionallyFuture.thenAccept(result -> System.out.println("Result: " + result));
    }
}
  1. 在这个例子中,我们创建了一个CompletableFuture对象future,它执行一个可能抛出异常的操作。在这个例子中,我们用Math.random()模拟了一个随机异常的情况。

  2. 然后,我们使用exceptionally方法来处理异常情况。exceptionally方法接受一个函数作为参数,该函数会在CompletableFuture出现异常时被调用,并返回一个默认的结果。

  3. 在这个例子中,我们将异常信息打印出来,并返回一个默认值-1作为结果。

  4. 最后,我们使用thenAccept方法来处理最终的结果,并将其打印出来。

  5. 这个例子展示了如何使用CompletableFuture的exceptionally方法来处理CompletableFuture对象可能抛出的异常情况。通过使用exceptionally方法,我们可以在出现异常时提供一个默认的结果,以便后续的处理。这种异常处理机制可以帮助我们更好地控制并发任务的执行流程。

4. 对多个CompletableFuture对象进行组合处理的方法:

这些方法可以对多个CompletableFuture对象进行组合处理。

4.1 allOf

allOf()方法可以等待所有CompletableFuture对象都完成。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureDemo {
    public static void main(String[] args) {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 10;
        });

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 20;
        });

        CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 30;
        });

        CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2, future3);

        try {
            allFutures.get();
            System.out.println("All tasks completed!");

            int result1 = future1.get();
            int result2 = future2.get();
            int result3 = future3.get();

            System.out.println("Result 1: " + result1);
            System.out.println("Result 2: " + result2);
            System.out.println("Result 3: " + result3);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}
  1. 在这个例子中,我们创建了三个CompletableFuture对象:future1、future2和future3。每个CompletableFuture对象都执行一个耗时的任务,通过调用Thread.sleep方法模拟延迟。

  2. 然后,我们使用CompletableFuture的allOf方法来等待所有CompletableFuture对象都完成。allOf方法返回一个CompletableFuture对象,表示所有任务的完成。

  3. 在等待所有任务完成后,我们通过调用get方法来获取每个任务的结果,并打印出来。

  4. 这个例子展示了如何使用CompletableFuture的allOf方法来同时执行多个CompletableFuture任务,并在所有任务都完成后进行后续操作。通过使用allOf方法,我们可以更好地控制并发任务的执行流程,并在所有任务完成后进行一些汇总或后续处理的操作。

4.2 anyOf

anyOf()方法可以等待任意一个CompletableFuture对象完成。

import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureDemo {

    public static void main(String[] args) {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(new Random().nextInt(5000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Result from CompletableFuture 1";
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(new Random().nextInt(5000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Result from CompletableFuture 2";
        });

        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(new Random().nextInt(5000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Result from CompletableFuture 3";
        });

        List<CompletableFuture<String>> futures = Arrays.asList(future1, future2, future3);

        CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(futures.toArray(new CompletableFuture[futures.size()]));

        try {
            Object result = anyFuture.get();
            System.out.println("Result: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}
  1. 在这个示例中,我们创建了三个CompletableFuture对象来模拟异步任务,每个任务都会休眠一段随机时间后返回一个结果。
    我们将这些CompletableFuture对象存储在一个列表中,并使用CompletableFuture的静态方法anyOf来创建一个新的CompletableFuture,该CompletableFuture将在任何一个原始CompletableFuture完成时完成。
  2. 在主线程中,我们使用anyFuture.get()方法来等待任何一个CompletableFuture完成,并获取其返回的结果。

5. 同步等待CompletableFuture对象完成的方法:

这些方法可以同步等待CompletableFuture对象的完成。

5.1 get#join

当使用CompletableFuture类时,可以使用get()和join()方法来获取计算结果。这两个方法之间的主要区别在于异常处理和返回值类型。

下面是一个使用CompletableFuture类的简单示例,展示了get()和join()方法的用法和区别:

import java.util.concurrent.*;

public class CompletableFutureDemo {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        // 创建一个CompletableFuture对象
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");

        // 使用get()方法获取结果
        String result1 = future.get();
        System.out.println("Result from get(): " + result1);

        // 使用join()方法获取结果
        String result2 = future.join();
        System.out.println("Result from join(): " + result2);
    }
}
  1. 在这个示例中,我们创建了一个CompletableFuture对象,并使用supplyAsync()方法在后台线程中执行一个简单的任务,返回字符串"Hello"。然后我们分别使用get()和join()方法来获取计算结果。

  2. 区别如下:

  • 异常处理:get()方法会抛出checked异常,需要使用try-catch块来处理可能的异常;而join()方法则会抛出unchecked异常,不需要显式处理异常。
  • 返回值类型:get()方法返回一个泛型类型的结果,可以将其赋值给一个变量;
    而join()方法返回一个与CompletableFuture对象关联的泛型类型的结果,不能直接赋值给一个变量。因此,如果只是想简单地获取结果,join()方法更加方便。
  1. 需要注意的是,get()和join()方法都是阻塞方法,即调用这些方法后,当前线程会一直等待,直到计算完成并返回结果。如果计算未完成,那么调用这些方法的线程将被阻塞。因此,在使用这些方法时要小心,以避免可能的死锁和性能问题。

三、CompletableFuture总结

CompletableFuture是Java 8引入的一个用于处理异步任务的工具类。它提供了一种简单而强大的方式来管理异步任务的执行和结果处理。

CompletableFuture具有以下特点和优势:

1. 异步执行:

CompletableFuture可以在后台线程中执行任务,不会阻塞主线程,提高了程序的执行效率。

2. 链式操作:

CompletableFuture支持链式操作,可以通过一系列的方法调用来对任务进行转换、处理和组合。这样可以方便地定义任务的处理流程,提高了代码的可读性和维护性。

3. 异常处理:

CompletableFuture提供了丰富的异常处理方法,可以对任务的异常进行处理。例如,可以通过exceptionally()方法指定任务失败时的默认返回值,通过handle()方法对任务的异常进行处理。

4. 组合处理:

CompletableFuture提供了多个方法来对多个CompletableFuture对象进行组合处理。例如,可以通过allOf()方法等待多个CompletableFuture对象都完成,通过anyOf()方法等待任意一个CompletableFuture对象完成。

5. 灵活性:

CompletableFuture提供了丰富的API,可以满足不同场景下的需求。通过合理使用这些方法,可以更加高效地处理异步任务的结果。

总之,CompletableFuture是一个功能强大且易于使用的工具类,可以帮助开发者更加方便地处理异步任务,提高程序的性能和可维护性。它是现代Java开发中不可或缺的一部分。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
CompletableFutureJava8引入的一个异步编程工具类,用于简化异步编程,提高代码可读性和可维护性。它可以让你在一个线程中进行异步编程,而无需显式地创建线程或使用回调函数。 CompletableFuture可以看作是对Future的扩展,它支持链式调用和组合操作,可以将多个CompletableFuture组合在一起,形成一个复杂的异步操作流程。它也提供了一些方法,比如thenApply、thenAccept、thenRun等,用于处理异步操作的结果。 在使用CompletableFuture时,我们可以将异步操作放在一个CompletableFuture对象中,然后通过链式调用的方式,将多个异步操作组合在一起,形成一个异步操作流程。当所有的异步操作都执行完毕后,可以使用CompletableFuture的get方法,获取异步操作的结果。 下面是一个使用CompletableFuture的示例代码: ```java CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { // 异步操作 return 10; }).thenApplyAsync(result -> { // 处理异步操作结果 return result * 2; }).thenApplyAsync(result -> { // 处理异步操作结果 return result + 3; }); // 获取异步操作的结果 Integer result = future.get(); ``` 在上面的代码中,我们首先使用CompletableFuture的supplyAsync方法,将异步操作放在一个CompletableFuture对象中。然后通过thenApplyAsync方法,将两个处理异步操作结果的函数串联在一起,形成一个异步操作流程。最后通过get方法,获取异步操作的结果。 除了thenApplyAsync方法,CompletableFuture还提供了许多其他的方法,比如thenAcceptAsync、thenRunAsync、thenComposeAsync等,可以根据具体需求来选择使用。 总之,CompletableFuture是一个非常强大的异步编程工具类,可以让你写出更加简洁、易读、易维护的异步代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Run,boy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值