首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >线程、线程池以及CompletableFuture组合式异步编程

线程、线程池以及CompletableFuture组合式异步编程

作者头像
shimeath
发布于 2021-01-05 06:51:45
发布于 2021-01-05 06:51:45
8030
举报

一、创建线程的三种常见方式

1、继承Thread

  1. 创建线程类,继承Thread
  2. new Thread().start()的方式启动线程
代码语言:javascript
AI代码解释
复制
public static void main(String[] args) {
    System.out.println("线程" + Thread.currentThread().getName() + "开始执行");
    new Thread(new Thread01(), "thread01").start();
    System.out.println("线程" + Thread.currentThread().getName() + "执行完毕");
}
static class Thread01 extends Thread {
    @Override
    public void run() {
        System.out.println("线程" + Thread.currentThread().getName() + "开始执行");
        int i = 10 / 5;
        System.out.println("计算结果为" + i);
    }
}

2、实现Runnable接口

  1. 创建线程类,实现Runnable接口
  2. new Thread(线程类).start()的方式启动线程
代码语言:javascript
AI代码解释
复制
public static void main(String[] args) {

    System.out.println("线程" + Thread.currentThread().getName() + "开始执行");
    new Thread(new Thread02(), "thread02").start();
    System.out.println("线程" + Thread.currentThread().getName() + "执行完毕");
}
static class Thread02 implements Runnable {
    @Override
    public void run() {
        System.out.println("线程" + Thread.currentThread().getName() + "开始执行");
        int i = 10 / 5;
        System.out.println("计算结果为" + i);
    }
}

3、实现Callable<T>接口

  1. 创建线程类,实现Callable接口,可以有返回值
  2. 创建FutureTask<T> futureTask = new FutureTask<>(线程类);
  3. new Thread(futureTask).start()的方式启动线程
  4. futureTask.get()获取返回值
代码语言:javascript
AI代码解释
复制
public static void main(String[] args) throws Exception {
    System.out.println("线程" + Thread.currentThread().getName() + "开始执行");
    FutureTask<String> stringFutureTask = new FutureTask<>(new Thread03());
    new Thread(stringFutureTask).start();
    System.out.println(stringFutureTask.get());
    System.out.println("线程" + Thread.currentThread().getName() + "执行完毕");
}
static class Thread03 implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println("线程" + Thread.currentThread().getName() + "开始执行");
        int i = 10 / 5;
        System.out.println("计算结果为" + 10);
        return "返回到主程序了" + i;
    }
}

二、使用线程池执行线程

1、Executors自带的线程池

固定大小线程池newFixedThreadPool
代码语言:javascript
AI代码解释
复制
// @param nThreads 线程数量,核心线程数和最大线程数均为该值
// @param threadFactory 创建线程的工厂
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>(),
                                  threadFactory);
}
单线程池,按序执行newSingleThreadExecutor
代码语言:javascript
AI代码解释
复制
// @param threadFactory 创建线程的工厂
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>(),
                                threadFactory));
}
可缓存的线程池,newCachedThreadPool
代码语言:javascript
AI代码解释
复制
// @nThreads 线程数量,核心线程数和最大线程数均为该值
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>(),
                                  threadFactory);
}

2、线程池的实现原理

所有Executors框架提供的线程池底层均为java.util.concurrent.ThreadPoolExecutor

代码语言:javascript
AI代码解释
复制
/**
 * 通过给定的参数创建一个线程池.
 *
 * @param corePoolSize 一直存活的线程数,即使空闲,除非设置了allowCoreThreadTimeOut。
 * @param maximumPoolSize 最大存活线程数
 * @param keepAliveTime 当前存活线程数大于核心线程数时,空闲线程等待新任务最大时间
 * @param unit 参数keepAliveTime的时间单位
 * @param workQueue 任务执行前保存任务的队列。只保存由execute方法提交的Runnable任务。
 * @param threadFactory 新建线程的线程工厂
 * @param handler 拒绝策略
 */
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.acc = System.getSecurityManager() == null ?
            null :
            AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

3、线程池的执行

  1. 创建线程池对象
  2. 使用线程池对象execute进行
代码语言:javascript
AI代码解释
复制
static ExecutorService executorService = Executors.newFixedThreadPool(4);

public static void main(String[] args) {
    System.out.println("线程" + Thread.currentThread().getName() + "开始执行");
    executorService.execute(new Thread01());  	// 没有返回值的异步执行
    executorService.execute(new Thread02());
    executorService.submit(new Thread01());		// 有返回值的异步执行
    executorService.submit(new Thread02());
    System.out.println("线程" + Thread.currentThread().getName() + "执行完毕");
}

三、CompletableFuture组合式异步编程

1、创建异步对象

(1)runAsync supplyAsync方法

CompletableFuture 提供了四个静态方法来创建一个异步操作。

  • runAsync方法不支持返回值。
  • supplyAsync可以支持返回值。
代码语言:javascript
AI代码解释
复制
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

(2) 计算结果完成时的回调方法

CompletableFuture的计算结果完成,或者抛出异常的时候,可以执行特定的Action。主要是下面的方法:

代码语言:javascript
AI代码解释
复制
//可以处理异常,无返回值
public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)

//可以处理异常,有返回值
public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)

可以看到Action的类型是BiConsumer<? super T,? super Throwable>它可以处理正常的计算结果,或者异常情况。

(3) handle 方法,任务完成后执行,可处理异常

handle 是执行任务完成时对结果的处理。 handle 方法和 thenApply 方法处理方式基本一样。不同的是 handle 是在任务完成后再执行,还可以处理异常的任务。thenApply 只可以执行正常的任务,任务出现异常则不执行 thenApply 方法。

代码语言:javascript
AI代码解释
复制
public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn,Executor executor);

(4) 线程串行化

等待之前任务完成后执行

  • thenApply:能接受上一步结果,有返回值
代码语言:javascript
AI代码解释
复制
public <U> CompletionStage<U> thenApply(Function<? super T, ? extends U> fn);
public <U> CompletionStage<U> thenApplyAsync(Function<? super T, ? extends U> fn);
public <U> CompletionStage<U> thenApplyAsync(Function<? super T, ? extends U> fn, Executor executor);
  • thenAccept:能接受上一步结果,但是无返回值
代码语言:javascript
AI代码解释
复制
public <U> CompletionStage<U> thenAccept(Consumer<? super T> action);
public <U> CompletionStage<U> thenAcceptAsync(Consumer<? super T> action);
public <U> CompletionStage<U> thenAcceptAsync(Consumer<? super T> action, Executor executor);
  • thenRun:不能获取上一步的执行结果
代码语言:javascript
AI代码解释
复制
public <U> CompletionStage<U> thenRun(Runnable action);
public <U> CompletionStage<U> thenRunAsync(Runnable action);
public <U> CompletionStage<U> thenRunAsync(Runnable action, Executor executor);

(5) 合并任务,都要完成

thenCombine:组合两个future,获取两个的结果,返回当前任务的返回值

代码语言:javascript
AI代码解释
复制
public <U,V> CompletableFuture<V> thenCombine(
    CompletionStage<? extends U> other,
    BiFunction<? super T,? super U,? extends V> fn);

public <U,V> CompletableFuture<V> thenCombineAsync(
    CompletionStage<? extends U> other,
    BiFunction<? super T,? super U,? extends V> fn);

public <U,V> CompletableFuture<V> thenCombineAsync(
    CompletionStage<? extends U> other,
    BiFunction<? super T,? super U,? extends V> fn, Executor executor);

thenAcceptBoth:组合两个future,获取结果,然后处理任务,没有返回值

代码语言:javascript
AI代码解释
复制
public <U> CompletableFuture<Void> thenAcceptBoth(
    CompletionStage<? extends U> other,
    BiConsumer<? super T, ? super U> action);

public <U> CompletableFuture<Void> thenAcceptBothAsync(
    CompletionStage<? extends U> other,
    BiConsumer<? super T, ? super U> action);

public <U> CompletableFuture<Void> thenAcceptBothAsync(
    CompletionStage<? extends U> other,
    BiConsumer<? super T, ? super U> action, Executor executor);

runAfterBoth:组合两个future,不需要获取结果,只需要两个future执行完成后就执行该任务

代码语言:javascript
AI代码解释
复制
public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,
                                            Runnable action);

public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
                                                 Runnable action);

public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
                                                 Runnable action,
                                                 Executor executor);

(6) 合并任务,仅完成一个

applyToEither:组合两个future完成其中一个执行,获取它的结果,返回当前任务的返回值

代码语言:javascript
AI代码解释
复制
public <U> CompletableFuture<U> applyToEither(
    CompletionStage<? extends T> other, Function<? super T, U> fn);

public <U> CompletableFuture<U> applyToEitherAsync(
    CompletionStage<? extends T> other, Function<? super T, U> fn);

public <U> CompletableFuture<U> applyToEitherAsync(
    CompletionStage<? extends T> other, Function<? super T, U> fn,
    Executor executor);

acceptEither:组合两个future完成其中一个执行,获取一个的结果,然后处理任务,没有返回值

代码语言:javascript
AI代码解释
复制
public CompletableFuture<Void> acceptEither(
    CompletionStage<? extends T> other, Consumer<? super T> action);

public CompletableFuture<Void> acceptEitherAsync(
    CompletionStage<? extends T> other, Consumer<? super T> action);

public CompletableFuture<Void> acceptEitherAsync(
    CompletionStage<? extends T> other, Consumer<? super T> action,
    Executor executor);

runAfterEither:组合两个future完成其中一个执行,不需要获取结果,只需要一个future执行完成后就执行该任务

代码语言:javascript
AI代码解释
复制
public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,
                                            Runnable action);

public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
                                                 Runnable action);

public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
                                                 Runnable action,
                                                 Executor executor);

(7) 多任务组合

allOf:等待所有任务完成

代码语言:javascript
AI代码解释
复制
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs);

anyOf:只要有一个完成

代码语言:javascript
AI代码解释
复制
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs);
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-12-31 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【小家Java】Future、FutureTask、CompletionService、CompletableFuture解决多线程并发中归集问题的效率对比
开启线程执行任务,不管是使用Runnable(无返回值不支持上报异常)还是Callable(有返回值支持上报异常)接口,都可以轻松实现。那么如果是开启线程池并需要获取结果归集的情况下,如何实现,以及优劣?
YourBatman
2019/09/03
2.9K1
【小家Java】Future、FutureTask、CompletionService、CompletableFuture解决多线程并发中归集问题的效率对比
一网打尽异步神器CompletableFuture
最近一直畅游在RocketMQ的源码中,发现在RocketMQ中很多地方都使用到了CompletableFuture,所以今天就跟大家来聊一聊JDK1.8提供的异步神器CompletableFuture,并且最后会结合RocketMQ源码分析一下CompletableFuture的使用。
三友的java日记
2022/07/27
7860
一网打尽异步神器CompletableFuture
Java8新的异步编程方式 CompletableFuture(二)
上一篇文章,讲述了Future模式的机制、缺点,CompletableFuture产生的由来、静态工厂方法、complete()方法等等。
fengzhizi715
2018/08/24
1.5K0
CompletableFuture 使用详解
没有指定Executor的方法会使用ForkJoinPool.commonPool() 作为它的线程池执行异步代码。如果指定线程池,则使用指定的线程池运行。以下所有的方法都类同。
java404
2018/10/10
4.2K1
并发编程 - CompletableFuture
常见的线程创建方式有两种,一是直接继承Thread,另一种是实现Runnable接口。但这两种方式有个缺点,不支持获取线程执行结果。
小小工匠
2023/08/02
4470
并发编程 - CompletableFuture
基础篇:异步编程不会?我教你啊!CompeletableFuture
以前需要异步执行一个任务时,一般是用Thread或者线程池Executor去创建。如果需要返回值,则是调用Executor.submit获取Future。但是多个线程存在依赖组合,我们又能怎么办?可使用同步组件CountDownLatch、CyclicBarrier等;其实有简单的方法,就是用CompletableFuture
潜行前行
2020/12/11
9090
基础篇:异步编程不会?我教你啊!CompeletableFuture
CompletableFuture 应用实践
首先来看一个问题,如果要执行多个任务,每个任务会返回对应结果,现在需要所有任务执行完毕之后,将这些任务结果统一打印出来,该如何完成呢?注意尽量不要使用业务线程来等待多个任务的结果,也就是不要使用Future.get方式。
luoxn28
2020/12/02
7830
CompletableFuture 应用实践
(94) 组合式异步编程 / 计算机程序的思维逻辑
前面两节讨论了Java 8中的函数式数据处理,那是对38节到55节介绍的容器类的增强,它可以将对集合数据的多个操作以流水线的方式组合在一起。本节继续讨论Java 8的新功能,主要是一个新的类CompletableFuture,它是对65节到83节介绍的并发编程的增强,它可以方便地将多个有一定依赖关系的异步任务以流水线的方式组合在一起,大大简化多异步任务的开发。 之前介绍了那么多并发编程的内容,还有什么问题不能解决?CompletableFuture到底能解决什么问题?与之前介绍的内容有什么关系?具体如何使
swiftma
2018/02/01
7830
JUC并发—14.Future模式和异步编程分析二
CompletionStage表示任务执行的一个阶段,每个异步任务都会返回一个新的CompletionStage对象,可针对多个CompletionStage对象进行串行、并行、聚合等操作。简单来说,CompletionStage就是实现异步任务执行后的自动回调功能。
东阳马生架构
2025/05/07
1700
从 CompletableFuture 到异步编程
JDK 5 引入了 Future 模式。Future 接口是 Java 多线程 Future 模式的实现,在 java.util.concurrent 包中,可以来进行异步计算。虽然 Future 以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和我们的异步编程的初衷相违背,轮询的方式又会耗费无谓的 CPU 资源,而且也不能及时地得到计算结果,为什么不能用观察者设计模式当计算结果完成及时通知监听者呢?如 Netty、Guava 分别扩展了 Java 的 Future 接口,方便异步编程。
BUG弄潮儿
2021/04/12
1.4K0
有了Future为什么还要CompletableFuture?
cheese
2024/02/06
4300
有了Future为什么还要CompletableFuture?
【第十四篇】商城系统-异步处理利器-CompletableFuture
  上面的三种获取线程的方法是直接获取,没有对线程做相关的管理,这时可以通过线程池来更加高效的管理线程对象。
用户4919348
2022/10/04
4350
【第十四篇】商城系统-异步处理利器-CompletableFuture
CompletableFuture在RocketMQ中的使用实战!
今天想跟大家来聊一聊JDK1.8提供的异步神器CompletableFuture,
程序员蜗牛
2024/02/18
3130
CompletableFuture在RocketMQ中的使用实战!
【小家java】Java8新特性之---CompletableFuture的系统讲解和实例演示(使用CompletableFuture构建异步应用)
传统单线程环境下,调用函数是同步的,必须等待程序返回结果后,才可进行其他处理。因此为了提高系统整体的并发性能,引入了异步执行~
YourBatman
2019/09/03
4.2K0
【小家java】Java8新特性之---CompletableFuture的系统讲解和实例演示(使用CompletableFuture构建异步应用)
异步技巧之CompletableFuture
在上面的注释中我们能知道Future用来代表异步的结果,并且提供了检查计算完成,等待完成,检索结果完成等方法。简而言之就是提供一个异步运算结果的一个建模。它可以让我们把耗时的操作从我们本身的调用线程中释放出来,只需要完成后再进行回调。就好像我们去饭店里面吃饭,不需要你去煮饭,而你这个时候可以做任何事,然后饭煮好后就会回调你去吃。
用户5397975
2019/10/13
9270
CompletableFuture实现异步编排
场景:电商系统中获取一个完整的商品信息可能分为以下几步:①获取商品基本信息 ②获取商品图片信息 ③获取商品促销活动信息 ④获取商品各种类的基本信息 等操作,如果使用串行方式去执行这些操作,假设每个操作执行1s,那么用户看到完整的商品详情就需要4s的时间,如果使用并行方式执行这些操作,可能只需要1s就可以完成。所以这就是异步执行的好处。
科技新语
2023/02/01
1.7K0
Java多任务编排技术
JDK 5新增Future接口,用于处理异步计算结果。虽然Future提供异步执行任务能力,但是获取结果很不方便,要么通过Future#get阻塞调用线程,或者通过轮询 Future#isDone判断任务是否结束,再获取结果。
科技新语
2025/07/31
2580
Java多任务编排技术
CompletableFuture介绍
一个Future类是显示的完成,而且能被用作一个完成等级,通过它的完成触发支持的依赖函数和行为。当两个或多个线程要执行完成或取消操作时,只有一个能够成功。
HLee
2021/07/12
2.2K0
CompletableFuture介绍
提高效率,实现异步编程,我用CompletableFuture(上)
大家好,我是小高先生,这篇文章我将和大家一起学习Java并发编程中很重要的一个类-CompletableFuture。
小高先生
2024/02/01
3290
搞定 CompletableFuture,并发异步编程和编写串行程序还有什么区别?你们要的多图长文
你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it well enough
用户4172423
2020/07/21
1.3K0
推荐阅读
相关推荐
【小家Java】Future、FutureTask、CompletionService、CompletableFuture解决多线程并发中归集问题的效率对比
更多 >
LV.0
这个人很懒,什么都没有留下~
作者相关精选
领券
社区新版编辑器体验调研
诚挚邀请您参与本次调研,分享您的真实使用感受与建议。您的反馈至关重要,感谢您的支持与参与!
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
首页
学习
活动
专区
圈层
工具
MCP广场
首页
学习
活动
专区
圈层
工具
MCP广场