多线程系列(二十) -CompletableFuture使用详解

这篇具有很好参考价值的文章主要介绍了多线程系列(二十) -CompletableFuture使用详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、摘要

在上篇文章中,我们介绍了Future相关的用法,使用它可以获取异步任务执行的返回值。

我们再次回顾一下Future相关的用法。

public class FutureTest {

    public static void main(String[] args) throws Exception {
        long startTime = System.currentTimeMillis();
        // 创建一个线程池
        ExecutorService executor = Executors.newFixedThreadPool(1);

        // 提交任务并获得Future的实例
        Future<String> future = executor.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                // 执行下载某文件任务,并返回文件名称
                System.out.println("thread name:" +  Thread.currentThread().getName() + " 开始执行下载任务");
                Thread.sleep(200);
                return "xxx.png";
            }
        });

        //模拟主线程其它操作耗时
        Thread.sleep(300);

        // 通过阻塞方式,从Future中获取异步执行返回的结果
        String result = future.get();
        System.out.println("任务执行结果:" +  result);
        System.out.println("总共用时:" + (System.currentTimeMillis() - startTime) + "ms");

        // 任务执行完毕之后,关闭线程池
        executor.shutdown();
    }
}

运行结果如下:

thread name:pool-1-thread-1 开始执行下载任务
任务执行结果:xxx.png
总共用时:308ms

如果不采用线程执行,那么总共用时应该会是 200 + 300 = 500 ms,而采用线程来异步执行,总共用时是 308 ms。不难发现,通过Future和线程池的搭配使用,可以有效的提升程序的执行效率。

但是Future对异步执行结果的获取并不是很友好,要么调用阻塞方法get()获取结果,要么轮训调用isDone()方法是否等于true来判断任务是否执行完毕来获取结果,这两种方法都不算很好,因为主线程会被迫等待。

因此,从 Java 8 开始引入了CompletableFuture,它针对Future做了很多的改进,在实现Future接口相关功能之外,还支持传入回调对象,当异步任务完成或者发生异常时,自动调用回调对象方法。

下面我们一起来看看CompletableFuture相关的用法!

二、CompletableFuture 用法介绍

我们还是以上面的例子为例,改用CompletableFuture来实现,内容如下:

public class FutureTest2 {

    public static void main(String[] args) throws Exception {
        // 创建异步执行任务
        CompletableFuture<String> cf = CompletableFuture.supplyAsync(FutureTest2::download);

        // 如果执行成功,回调此方法
        cf.thenAccept((result) -> {
            System.out.println("任务执行成功,返回结果值:" +  result);
        });

        // 如果执行异常,回调此方法
        cf.exceptionally((e) -> {
            System.out.println("任务执行失败,原因:" +  e.getMessage());
            return null;
        });

        //模拟主线程其它操作耗时
        Thread.sleep(300);
    }

    /**
     * 下载某个任务
     * @return
     */
    private static String download(){
        // 执行下载某文件任务,并返回文件名称
        System.out.println("thread name:" +  Thread.currentThread().getName() + " 开始执行下载任务");
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "xxx.png";
    }
}

运行结果如下:

thread name:ForkJoinPool.commonPool-worker-1 开始执行下载任务
任务执行成功,返回结果值:xxx.png

可以发现,采用CompletableFuture类的supplyAsync()方法进行异步编程,代码上简洁了很多,不需要单独创建线程池。

实际上,CompletableFuture也使用了线程池来执行任务,部分核心源码如下:

public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {

    // 判断当前机器 cpu 可用逻辑核心数是否大于1
    private static final boolean useCommonPool = (ForkJoinPool.getCommonPoolParallelism() > 1);
    
    // 默认采用的线程池
    // 如果useCommonPool = true,采用 ForkJoinPool.commonPool 线程池
    // 如果useCommonPool = false,采用 ThreadPerTaskExecutor 执行器
    private static final Executor asyncPool = useCommonPool ?
        ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();

    // ThreadPerTaskExecutor执行器类
    static final class ThreadPerTaskExecutor implements Executor {
        public void execute(Runnable r) { new Thread(r).start(); }
    }


    // 异步执行任务的方法
    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
        return asyncSupplyStage(asyncPool, supplier);
    }

    // 异步执行任务的方法,支持传入自定义线程池
    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
                                                       Executor executor) {
        return asyncSupplyStage(screenExecutor(executor), supplier);
    }
}

从源码上可以分析出如下几点:

  • 当前机器 cpu 可用逻辑核心数大于 1,默认会采用ForkJoinPool.commonPool()线程池来执行任务
  • 当前机器 cpu 可用逻辑核心数等于 1,默认会采用ThreadPerTaskExecutor类来执行任务,它是个一对一执行器,每提交一个任务会创建一个新的线程来执行
  • 同时也支持用户传入自定义线程池来异步执行任务

其中ForkJoinPool线程池是从 JDK 1.7 版本引入的,它是一个全新的线程池,后面在介绍Fork/Join框架文章中对其进行介绍。

除此之外,CompletableFuture为开发者还提供了几十种方法,以便满足更多的异步任务执行的场景。这些方法包括创建异步任务、任务异步回调、多个任务组合处理等内容,下面我们就一起来学习一下相关的使用方式。

2.1、创建异步任务

CompletableFuture创建异步任务,常用的方法有两个。

  • runAsync():执行异步任务时,没有返回值
  • supplyAsync():执行异步任务时,可以带返回值

runAsync()supplyAsync()方法相关的源码如下:

// 使用默认内置线程池执行任务,根据runnable构建执行任务,无返回值
public static CompletableFuture<Void> runAsync(Runnable runnable)

// 使用自定义线程池执行任务,根据runnable构建执行任务,无返回值
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)

// 使用默认内置线程池执行任务,根据supplyAsync构建执行任务,可以带返回值
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)

// 使用自定义线程池执行任务,根据supplyAsync构建执行任务,可以带返回值
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

两者都支持使用自定义的线程池来执行任务,稍有不同的是supplyAsync()方法的入参使用的是Supplier接口,它表示结果的提供者,该结果返回一个对象且不接受任何参数,支持通过 lambda 语法简写

下面我们一起来看看相关的使用示例!

2.1.1、runAsync 使用示例
public static void main(String[] args) throws Exception {
    // 创建异步执行任务
    CompletableFuture<Void> cf = CompletableFuture.runAsync(new Runnable() {
        @Override
        public void run() {
            System.out.println("runAsync,执行完毕");
        }
    });
    System.out.println("runAsync,任务执行结果:" + cf.get());
}

输出结果:

runAsync,执行完毕
runAsync,任务执行结果:null
2.1.2、supplyAsync 使用示例
public static void main(String[] args) throws Exception {
    // 创建异步执行任务
    CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync,执行完毕");
        return "hello world";
    });
    System.out.println("supplyAsync,任务执行结果:" + cf.get());
}

输出结果:

supplyAsync,执行完毕
supplyAsync,任务执行结果:hello world

2.2、任务异步回调

当创建的异步任务执行完毕之后,我们希望拿着上一个任务的执行结果,继续执行后续的任务,此时就可以采用回调方法来处理。

CompletableFuture针对任务异步回调做了很多的支持,常用的方法如下:

  • thenRun()/thenRunAsync():它表示上一个任务执行成功后的回调方法,无入参,无返回值
  • thenAccept()/thenAcceptAsync():它表示上一个任务执行成功后的回调方法,有入参,无返回值
  • thenApply()/thenApplyAsync():它表示上一个任务执行成功后的回调方法,有入参,有返回值
  • whenComplete()/whenCompleteAsync():它表示任务执行完成后的回调方法,有入参,无返回值
  • handle()/handleAsync():它表示任务执行完成后的回调方法,有入参,有返回值
  • exceptionally():它表示任务执行异常后的回调方法

下面我们一起来看看相关的使用示例!

2.2.1、thenRun/thenRunAsync

thenRun()/thenRunAsync()方法,都表示上一个任务执行成功后的回调处理,无入参,无返回值。稍有不同的是,thenRunAsync()方法会采用独立的线程池来执行任务。

相关的源码方法如下:

// 默认线程池
private static final Executor asyncPool = useCommonPool ?
        ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();

// 采用与上一个任务的线程池来执行任务
public CompletableFuture<Void> thenRun(Runnable action) {
    return uniRunStage(null, action);
}

// 采用默认线程池来执行任务
public CompletableFuture<Void> thenRunAsync(Runnable action) {
    return uniRunStage(asyncPool, action);
}

从源码上可以清晰的看到,thenRun()/thenRunAsync()方法都调用了uniRunStage()方法,不同的是thenRunAsync()使用了asyncPool参数,也就是默认的线程池;而thenRun()方法使用的是null,底层采用上一个任务的线程池来执行,总结下来就是:

  • 当调用thenRun()方法执行任务时,当前任务和上一个任务都共用同一个线程池
  • 当调用thenRunAsync()方法执行任务时,上一个任务采用自己的线程池来执行;而当前任务会采用默认线程池来执行,比如ForkJoinPool

thenAccept()/thenAcceptAsync()thenApply()/thenApplyAsync()whenComplete()/whenCompleteAsync()handle()/handleAsync()方法之间的区别也类似,下文不再重复讲解。

下面我们一起来看看thenRun()方法的使用示例。

public static void main(String[] args) throws Exception {
    // 创建异步执行任务
    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync,执行完毕");
        return "hello world";
    });

    // 当上一个任务执行成功,会继续回调当前方法
    CompletableFuture<Void> cf2 = cf1.thenRun(() -> {
        System.out.println("thenRun1,执行完毕");

    });

    CompletableFuture<Void> cf3 = cf2.thenRun(() -> {
        System.out.println("thenRun2,执行完毕");
    });


    System.out.println("任务执行结果:" + cf3.get());
}

输出结果:

supplyAsync,执行完毕
thenRun1,执行完毕
thenRun2,执行完毕
任务执行结果:null

如果上一个任务执行异常,是不会回调thenRun()方法的,示例如下:

public static void main(String[] args) throws Exception {
    // 创建异步执行任务
    CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync,执行完毕");
        if(1 == 1){
            throw new RuntimeException("执行异常");
        }
        return "hello world";
    });

    // 当上一个任务执行成功,会继续回调当前方法
    CompletableFuture<Void> cf1 = cf.thenRun(() -> {
        System.out.println("thenRun1,执行完毕");

    });

    // 监听执行时异常的回调方法
    CompletableFuture<Void> cf2 = cf1.exceptionally((e) -> {
        System.out.println("发生异常,错误信息:" + e.getMessage());
        return null;
    });

    System.out.println("任务执行结果:" + cf2.get());
}

输出结果:

supplyAsync,执行完毕
发生异常,错误信息:java.lang.RuntimeException: 执行异常
任务执行结果:null

可以清晰的看到,thenRun()方法没有回调。

thenAccept()thenAcceptAsync()thenApply()thenApplyAsync()方法也类似,当上一个任务执行异常,不会回调这些方法。

2.2.2、thenAccept/thenAcceptAsync

thenAccept()/thenAcceptAsync()方法,表示上一个任务执行成功后的回调方法,有入参,无返回值。

相关的示例如下。

public static void main(String[] args) throws Exception {
    // 创建异步执行任务
    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync,执行完毕");
        return "hello world";
    });

    // 当上一个任务执行成功,会继续回调当前方法
    CompletableFuture<Void> cf2 = cf1.thenAccept((r) -> {
        System.out.println("thenAccept,执行完毕,上一个任务执行结果值:" + r);

    });

    System.out.println("任务执行结果:" + cf2.get());
}

输出结果:

supplyAsync,执行完毕
thenAccept,执行完毕,上一个任务执行结果值:hello world
任务执行结果:null
2.2.3、thenApply/thenApplyAsync

thenApply()/thenApplyAsync()方法,表示上一个任务执行成功后的回调方法,有入参,有返回值。

相关的示例如下。

public static void main(String[] args) throws Exception {
    // 创建异步执行任务
    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync,执行完毕");
        return "hello world";
    });

    // 当上一个任务执行成功,会继续回调当前方法
    CompletableFuture<String> cf2 = cf1.thenApply((r) -> {
        System.out.println("thenApply,执行完毕,上一个任务执行结果值:" + r);
        return "gogogo";
    });

    System.out.println("任务执行结果:" + cf2.get());
}

输出结果:

supplyAsync,执行完毕
thenApply,执行完毕,上一个任务执行结果值:hello world
任务执行结果:gogogo
2.2.4、whenComplete/whenCompleteAsync

whenComplete()/whenCompleteAsync()方法,表示任务执行完成后的回调方法,有入参,无返回值。

稍有不同的是:无论任务执行成功还是失败,它都会回调。

相关的示例如下。

public static void main(String[] args) throws Exception {
    // 创建异步执行任务
    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync,执行完毕");
        if(1 == 1){
            throw new RuntimeException("执行异常");
        }
        return "hello world";
    });

    // 当任务执行完成,会继续回调当前方法
    CompletableFuture<String> cf2 = cf1.whenComplete((r, e) -> {
        System.out.println("whenComplete,执行完毕,上一个任务执行结果值:" + r + ",异常信息:" + e.getMessage());
    });

    // 监听执行时异常的回调方法
    CompletableFuture<String> cf3 = cf2.exceptionally((e) -> {
        System.out.println("发生异常,错误信息:" + e.getMessage());
        return e.getMessage();
    });

    System.out.println("任务执行结果:" + cf3.get());
}

输出结果:

supplyAsync,执行完毕
whenComplete,执行完毕,上一个任务执行结果值:null,异常信息:java.lang.RuntimeException: 执行异常
发生异常,错误信息:java.lang.RuntimeException: 执行异常
任务执行结果:java.lang.RuntimeException: 执行异常
2.2.5、handle/handleAsync

handle()/handleAsync()方法,表示任务执行完成后的回调方法,有入参,有返回值。

同样的,无论任务执行成功还是失败,它都会回调。

相关的示例如下。

public static void main(String[] args) throws Exception {
    // 创建异步执行任务
    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync,执行完毕");
        if(1 == 1){
            throw new RuntimeException("执行异常");
        }
        return "hello world";
    });

    // 当任务执行完成,会继续回调当前方法
    CompletableFuture<String> cf2 = cf1.handle((r, e) -> {
        System.out.println("handle,执行完毕,上一个任务执行结果值:" + r + ",异常信息:" + e.getMessage());
        return "handle";
    });
    
    System.out.println("任务执行结果:" + cf2.get());
}

输出结果:

supplyAsync,执行完毕
handle,执行完毕,上一个任务执行结果值:null,异常信息:java.lang.RuntimeException: 执行异常
任务执行结果:handle
2.2.6、exceptionally

exceptionally()方法,表示任务执行异常后的回调方法。在上文的示例中有所介绍。

最后我们还是简单的看下示例。

public static void main(String[] args) throws Exception {
    // 创建异步执行任务
    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync,执行开始");
        if(1 == 1){
            throw new RuntimeException("执行异常");
        }
        return "hello world";
    });

    // 监听执行时异常的回调方法
    CompletableFuture<String> cf2 = cf1.exceptionally((e) -> {
        System.out.println("发生异常,错误信息:" + e.getMessage());
        return e.getMessage();
    });

    System.out.println("任务执行结果:" + cf2.get());
}

输出结果:

supplyAsync,执行开始
发生异常,错误信息:java.lang.RuntimeException: 执行异常
任务执行结果:java.lang.RuntimeException: 执行异常

2.3、多个任务组合处理

某些场景下,如果希望获取两个不同的异步执行结果进行组合处理,可以采用多个任务组合处理方式。

CompletableFuture针对多个任务组合处理做了很多的支持,常用的组合方式有以下几种。

  • AND组合:表示将两个CompletableFuture任务组合起来,只有这两个任务都正常执行完了,才会继续执行回调任务,比如thenCombine()方法
  • OR组合:表示将两个CompletableFuture任务组合起来,只要其中一个正常执行完了,就会继续执行回调任务,比如applyToEither方法
  • AllOf组合:可以将多个CompletableFuture任务组合起来,只有所有的任务都正常执行完了,才会继续执行回调任务,比如allOf()方法
  • AnyOf组合:可以将多个CompletableFuture任务组合起来,只要其中一个任务正常执行完了,就会继续执行回调任务,比如anyOf()方法

下面我们一起来看看相关的使用示例!

2.3.1、AND组合

实现AND组合的操作方法有很多,比如runAfterBoth()thenAcceptBoth()thenCombine()等方法,它们之间的区别在于:是否带有入参、是否带有返回值。

其中thenCombine()方法支持传入参、带返回值。

相关示例如下:

public static void main(String[] args) throws Exception {
    // 创建异步执行任务
    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync1,执行完毕");
        return "supplyAsync1";
    });

    CompletableFuture<String> cf2 = CompletableFuture
            .supplyAsync(() -> {
                System.out.println("supplyAsync2,执行完毕");
                return "supplyAsync2";
            })
            .thenCombine(cf1, (r1, r2) -> {
                System.out.println("r1任务执行结果:" + r1);
                System.out.println("r2任务执行结果:" + r2);
                return r1 + "_" + r2;
            });

    System.out.println("任务执行结果:" + cf2.get());
}

输出结果:

supplyAsync1,执行完毕
supplyAsync2,执行完毕
r1任务执行结果:supplyAsync2
r2任务执行结果:supplyAsync1
任务执行结果:supplyAsync2_supplyAsync1
2.3.2、OR组合

实现OR组合的操作方法有很多,比如runAfterEither()acceptEither()applyToEither()等方法,区别同上。

其中applyToEither()方法支持传入参、带返回值。

相关示例如下:

public static void main(String[] args) throws Exception {
    // 创建异步执行任务
    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync1,执行完毕");
        return "supplyAsync1";
    });

    CompletableFuture<String> cf2 = CompletableFuture
            .supplyAsync(() -> {
                System.out.println("supplyAsync2,执行完毕");
                return "supplyAsync2";
            })
            .applyToEither(cf1, (r) -> {
                System.out.println("第一个执行成功的任务结果:" + r);
                return r + "_applyToEither";
            });

    System.out.println("任务执行结果:" + cf2.get());
}

输出结果:

supplyAsync1,执行完毕
supplyAsync2,执行完毕
第一个执行成功的任务结果:supplyAsync2
任务执行结果:supplyAsync2_applyToEither
2.3.2、AllOf组合

实现AllOf组合的操作就一个方法allOf(),可以将多个任务进行组合,只有都执行成功才会回调,回调入参为空值。

相关示例如下:

public static void main(String[] args) throws Exception {
    // 创建异步执行任务
    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync1,执行完毕");
        return "supplyAsync1";
    });

    CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync2,执行完毕");
        return "supplyAsync2";
    });

    // 将多个任务,进行AND组合
    CompletableFuture<String> cf3 = CompletableFuture
            .allOf(cf1, cf2)
            .handle((r, e) -> {
                System.out.println("所有任务都执行成功,result:" +  r);
                return "over";
            });
    System.out.println(cf3.get());
}

输出结果:

supplyAsync1,执行完毕
supplyAsync2,执行完毕
所有任务都执行成功,result:null
over
2.3.3、AnyOf组合

实现AnyOf组合的操作,同样就一个方法anyOf(),可以将多个任务进行组合,只要一个执行成功就会回调,回调入参有值。

相关示例如下:

public static void main(String[] args) throws Exception {
    // 创建异步执行任务
    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync1,执行完毕");
        return "supplyAsync1";
    });

    CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync2,执行完毕");
        return "supplyAsync2";
    });

    // 将多个任务,进行AND组合
    CompletableFuture<String> cf3 = CompletableFuture
            .anyOf(cf1, cf2)
            .handle((r, e) -> {
                System.out.println("某个任务执行成功,返回值:" + r);
                return "over";
            });
    System.out.println(cf3.get());
}

输出结果:

supplyAsync1,执行完毕
supplyAsync2,执行完毕
某个任务执行成功,返回值:supplyAsync1
over

三、小结

本文主要围绕CompletableFuture类相关用法进行了一次知识总结,通过CompletableFuture类可以简化异步编程,同时支持多种异步任务,按照条件组合处理,相比其它的并发工具类,操作更加强大、实用。

本篇内容比较多,如果有描述不对的地方,欢迎网友留言指出,希望本文知识总结能帮助到大家。

四、参考

1.https://www.liaoxuefeng.com/wiki/1252599548343744/1306581182447650

2.https://juejin.cn/post/6970558076642394142文章来源地址https://www.toymoban.com/news/detail-840158.html

到了这里,关于多线程系列(二十) -CompletableFuture使用详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 多线程系列(四) -volatile关键字使用详解

    在上篇文章中,我们介绍到在多线程环境下,如果编程不当,可能会出现程序运行结果混乱的问题。 出现这个原因主要是,JMM 中主内存和线程工作内存的数据不一致,以及多个线程执行时无序,共同导致的结果。 同时也提到引入 synchronized 同步锁,可以保证线程同步,让多

    2024年02月21日
    浏览(58)
  • JavaScript系列从入门到精通系列第二十篇:使用工厂方法创建JavaScript对象,JavaScript构造函数详解,JavaScript类概念的介绍

    文章目录 一:使用工厂方法创建对象 1:原始写法 2:工厂方式 3:结果验证  二:构造函数 1:什么是构造函数 2:构造函数和普通函数的区别 3:构造函数的执行流程 三:类 1:什么是类 2:如何检查一个对象是否是个类的实例 3:Object的地位 四:构造函数修改 1:重大问题

    2024年02月08日
    浏览(43)
  • CompletableFuture使用详解(全网看这一篇就行)

    CompletableFuture是jdk8的新特性。CompletableFuture实现了CompletionStage接口和Future接口,前者是对后者的一个扩展,增加了异步会点、流式处理、多个Future组合处理的能力,使Java在处理多任务的协同工作时更加顺畅便利。 1. supplyAsync supplyAsync是创建带有返回值的异步任务。它有如下两

    2024年02月03日
    浏览(48)
  • CompletableFuture解决多线程返回结果问题

    在Java中CompletableFuture用于异步编程,异步编程是编写非阻塞的代码,运行的任务在一个单独的线程,与主线程隔离,并且会通知主线程它的进度,成功或者失败。 在这种方式中,主线程不会被阻塞,不需要一直等到子线程完成。主线程可以并行的执行其他任务。 使用这种并

    2024年02月16日
    浏览(48)
  • SpringBoot多线程异步任务:ThreadPoolTaskExecutor + CompletableFuture

    在 SpringBoot 项目中,一个任务比较复杂,执行时间比较长,需要采用 多线程异步 的方式执行,从而缩短任务执行时间。 将任务拆分成多个独立的子任务,每个子任务在独立子线程中执行; 当所有子任务的子线程全部执行完成后,将几个子任务汇总,得到总任务的执行结果。

    2024年02月10日
    浏览(49)
  • Java的CompletableFuture,Java的多线程开发

    如下图: 以后用到再加 get() 和 join() 方法区别? 都可以阻塞线程 —— 等所有任务都执行完了再执行后续代码。 anyOf() 和 allOf() 的区别? 无返回值 推荐: 开启多线程——无返回值的——阻塞 :test06 有返回值 推荐:开启多线程——有返回值的,返回一个新的List——阻塞—

    2024年02月06日
    浏览(46)
  • 「Java」《深入解析Java多线程编程利器:CompletableFuture》

    多线程编程是指在一个程序中同时执行多个线程来提高系统的并发性和响应性。在现代计算机系统中,多线程编程已经成为开发者日常工作的一部分。以下是对多线程编程需求和挑战的介绍: 需求: 提高系统的性能:通过同时执行多个线程,可以利用多核处理器的优势,实

    2024年02月11日
    浏览(50)
  • CompletableFuture与线程池:Java 8中的高效异步编程搭配

    摘要:在Java 8中,CompletableFuture和线程池的结合使用为程序员提供了一种高效、灵活的异步编程解决方案。本文将深入探讨CompletableFuture和线程池结合使用的优势、原理及实际应用案例,帮助读者更好地理解并掌握这一技术。 随着多核处理器的普及,应用程序的性能和响应能

    2024年02月07日
    浏览(62)
  • 【CompletableFuture任务编排】游戏服务器线程模型及其线程之间的交互(以排行榜线程和玩家线程的交互为例子)

    需求: 1.我们希望玩家的业务在玩家线程执行,无需回调,因此是多线程处理。 2.匹配线程负责匹配逻辑,是单独一个线程。 3.排行榜线程负责玩家的上榜等。 4.从排行榜线程获取到排行榜列表后,需要给玩家发奖修改玩家数据,因此涉及到排行榜线程和玩家线程的交互。

    2024年01月22日
    浏览(47)
  • 【二十四】springboot使用EasyExcel和线程池实现多线程导入Excel数据

      springboot篇章整体栏目:  【一】springboot整合swagger(超详细 【二】springboot整合swagger(自定义)(超详细) 【三】springboot整合token(超详细) 【四】springboot整合mybatis-plus(超详细)(上) 【五】springboot整合mybatis-plus(超详细)(下) 【六】springboot整合自定义全局异常

    2023年04月08日
    浏览(68)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包