【JAVA多线程】Future,专为异步编程而生

news2024/9/20 10:56:51

目录

1.Future

2.CompletableFuture

2.1.为什么会有CompletableFuture?

2.2.使用

2.2.1.提交任务+获取结果

2.2.2.回调函数

2.2.3.CompletableFuture嵌套问题


1.Future

Java中的Future接口代表一个异步计算。其提供了一组规范用来对异步计算任务进行管理控制。

  • V get(): 阻塞等待计算完成,然后返回结果。如果计算抛出了异常,则此方法将重新抛出该异常。它有两个重载版本,区别是是否允许设置阻塞超时的时间。

  • boolean isDone(): 返回true如果任务已完成(无论是否成功),否则返回false。这包括正常完成、被取消或执行时抛出异常的情况。

  • boolean cancel(boolean mayInterruptIfRunning): 尝试取消任务的执行。如果任务尚未开始,它将被取消;如果任务正在运行且mayInterruptIfRunning为true,则执行该任务的线程将被中断;如果任务已经完成,取消请求将被忽略。此方法返回true表示任务已被取消,无论是之前已取消还是由于此次调用而取消。

  • boolean isCancelled(): 如果任务在正常完成前被取消,则返回true。

代码示例:

下面为了演示的全面一点,会把经常用到的api都调用一遍,其实直接get就能去拿值了。isDone和isCancelled只是为了保险起见而已。

import java.util.concurrent.*;
​
public class FutureAPIDemo {
​
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(1);
​
        Future<String> future = executor.submit(() -> {
            Thread.sleep(2000); // 模拟耗时操作
            return "Hello from Future!";
        });
​
        // 检查任务是否完成
        while (!future.isDone()) {
            System.out.println("Task is not done yet...");
            try {
                Thread.sleep(500); // 让主线程等待一段时间
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
​
        // 尝试获取结果
        if (!future.isCancelled()) {
            try {
                String result = future.get(); // 这里会阻塞直到获取到结果
                System.out.println("Result: " + result);
            } catch (InterruptedException | ExecutionException e) {
                System.err.println("Error getting result: " + e.getMessage());
            }
        } else {
            System.out.println("Task was cancelled.");
        }
​
        // 尝试取消任务(实际在这个例子中不会改变状态,因为任务已经完成)
        boolean cancellationResult = future.cancel(true);
        System.out.println("Cancellation attempt result: " + cancellationResult);
​
        executor.shutdown();
    }
}

Future接口只规定了规范,具体实现是什么样子的喃?Future怎么就能去控制异步任务了?我们具体选一个实现类来看看,可以看到JDK种带了很多Future的实现:

我们选FutureTask:

public class FutureTask<V> implements RunnableFuture<V>

可以看到FutureTask其实就是一条线程:

其实异步任务本质上就是一条线程脱离主线程另起炉灶去跑一个方法逻辑。

public interface RunnableFuture<V> extends Runnable, Future<V>

然后用一个函数式接口指向业务逻辑,有很多状态字段,通过状态去控制线程以及整个异步任务的退出和任务获取等,以get方法为例:

public class FutureTask<V> implements RunnableFuture<V> {
    private volatile int state;
    private static final int NEW          = 0;
    private static final int COMPLETING   = 1;
    private static final int NORMAL       = 2;
    private static final int EXCEPTIONAL  = 3;
    private static final int CANCELLED    = 4;
    private static final int INTERRUPTING = 5;
    private static final int INTERRUPTED  = 6;
​
    private Callable<V> callable;
    private Object outcome; // non-volatile, protected by state reads/writes
    private volatile Thread runner;
    private volatile WaitNode waiters;
​
    public V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (unit == null)
            throw new NullPointerException();
        int s = state;
        if (s <= COMPLETING &&
            (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
            throw new TimeoutException();
        return report(s);
    }
    
    ......
}

2.CompletableFuture

2.1.为什么会有CompletableFuture?

future只是实现了基础的异步编程而已,但是其性能仍然可以优化,其使用上还可以扩展能多能力,completableFuture可以理解为future的升级版本:

  • CompletableFuture 提供了一系列方法,如thenApply, thenCompose, thenCombine等,允许你轻松地组合多个异步操作,构建复杂的异步工作流。相比之下,Future仅提供了获取结果或取消任务的基本功能。
  • CompletableFuture 支持注册回调函数,当异步操作完成时自动执行这些函数,无需显式调用get()方法阻塞主线程。这使得代码更易于编写和理解,避免了“回调地狱”。
  • CompletableFuture 内部使用了ForkJoinPool或其他线程池,这通常比手动管理线程更高效。此外,CompletableFuture的实现考虑了并发场景下的性能优化。

2.2.使用

2.2.1.提交任务+获取结果

CompletableFuture支持两种提交任务的方式:

  • runAsync

  • supplyAsync

两者的区别是前者没有返回值,后者有返回值。

不管是runAsync也好,还是supplyAsync也好,他们用来接收任务的参数都是一个函数式接口,这意味着什么喃?意味着可以直接通过lambda表达式来定义任务。

获取结果和Future是一样的,如果没有获取到任务的结果,就会一直阻塞,直到获取到为止。

以下以runAsync为例做一个代码演示:

CompletableFuture completableFuture = CompletableFuture.runAsync(() -> {
    try {
        Thread.sleep(1000);
    } catch (Exception e) {
        e.printStackTrace();
    }
});
completableFuture.get();//这里会阻塞,直到任务执行完成

2.2.2.回调函数

当任务执行完成后,我们期待有后续的关联操作,就需要用上回调函数了。CompletableFuture比起Future来说用起来很方便的一点就是CompletableFuture支持回调函数。

CompletableFuture支持三种回调函数:

  • thenRun,无参无返回。

  • thenAccept,有参无返回。

  • thenApply,有参有返回。

以下是代码示例:

thenRun:

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

public class CompletableFutureExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("CompletableFuture is done.");
            return null;
        }).thenRun(() -> System.out.println("Task completed."));

        future.get(); // 等待任务完成
    }
}

thenAccept:

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

public class CompletableFutureExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "Hello, CompletableFuture!";
        }).thenAccept(result -> System.out.println("Result: " + result));

        future.get(); // 等待任务完成
    }
}

thenApply:

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

public class CompletableFutureExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "Hello, CompletableFuture!";
        }).thenApply(result -> result.toUpperCase());

        System.out.println(future.get()); // 输出: HELLO, COMPLETABLEFUTURE!
    }
}

2.2.3.CompletableFuture嵌套问题

CompletableFuture存在嵌套问题,举个例:

以上两个函数的返回值都是一个CompletableFuture,链式调用它们就会现成一个CompletableFuture嵌套:

CompletableFuture提供了对CompletableFuture编排的API,支持对多个CompletableFuture做聚合操作,如下我们可以调用thenCompose来将多层嵌套展开:

CompletableFuture一共提供了四种对CompletableFuture进行编排的API:

  • thenCompose,对多个CompletableFuture进行链式编排。

  • thenCombine,对两个CompletableFuture进行map操作。

  • allof,将多个任务聚合成一个任务集,集合中全部任务完成后才能继续往下走。

  • anyof,将多个任务聚合成一个任务集,集合中任意一个任务完成后就能继续往下走。

以下是代码示例:

thenCompose:

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

public class CompletableFutureComposition {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "First Result";
        });

        CompletableFuture<String> secondFuture = firstFuture.thenCompose(s -> CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return s + " Second Result";
        }));

        System.out.println(secondFuture.get());
    }
}

thenCombine:

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

public class CompletableFutureComposition {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "First Result";
        });

        CompletableFuture<String> secondFuture = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "Second Result";
        });

        CompletableFuture<String> combinedFuture = firstFuture.thenCombine(secondFuture, (s1, s2) -> s1 + " " + s2);

        System.out.println(combinedFuture.get());
    }
}

allOf:

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

public class CompletableFutureComposition {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Void> firstFuture = CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("First task done");
        });

        CompletableFuture<Void> secondFuture = CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("Second task done");
        });

        CompletableFuture<Void> allFutures = CompletableFuture.allOf(firstFuture, secondFuture);

        allFutures.get();
        System.out.println("All tasks are done");
    }
}

anyOf:

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

public class CompletableFutureComposition {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Void> firstFuture = CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("First task done");
        });

        CompletableFuture<Void> secondFuture = CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("Second task done");
        });

        CompletableFuture<Void> anyFuture = CompletableFuture.anyOf(firstFuture, secondFuture);

        anyFuture.get();
        System.out.println("At least one task is done");
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1939329.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java项目(knife4j使用,静态资源未放在static资源包下,公共字段自动填充,Spring Cache与Spring Task)

Knife4j&#xff08;生成接口文档&#xff09; 使用swagger你只需要按照它的规范去定义接口及接口相关的信息&#xff0c;就可以做到生成接口文档&#xff0c;以及在线接口调试页面。官网:https://swagger.io/ Knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案。…

uni-app 影视类小程序开发从零到一 | 开源项目推荐

引言 在数字娱乐时代&#xff0c;对于电影爱好者而言&#xff0c;随时随地享受精彩影片成为一种日常需求。分享一款基于 uni-app 开发的影视类小程序。它不仅提供了丰富的影视资源推荐&#xff0c;还融入了个性化知乎日报等内容&#xff0c;是不错的素材&#xff0c;同时对电影…

Springboot同时支持http和https访问

springboot默认是http的 一、支持https访问 需要生成证书&#xff0c;并配置到项目中。 1、证书 如果公司提供&#xff0c;则直接使用公司提供的证书&#xff1b; 如果公司没有提供&#xff0c;也可自己使用Java自带的命令keytool来生成&#xff1a; &#xff08;1&#x…

JavaWeb笔记_Cookie

一.会话技术概述 在日常生活中,A和B之间在打电话过程中一连串的你问我答就是一个会话 在BS模型中,会话可以理解为通过浏览器访问服务端的资源,点击超链接可以进行资源的跳转,直到浏览器关闭过程叫做会话 我们使用会话技术可以解决的是整个会话过程中(通过浏览器浏览服务…

【Linux】一文向您详细介绍 Vim编辑器 显示行号的方法

【Linux】一文向您详细介绍 Vim编辑器 显示行号的方法 下滑即可查看博客内容 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1a;985高校的普通本…

【Matlab】PLS偏最小二乘法回归预测算法(附代码)

资源下载&#xff1a; 资源合集&#xff1a; 目录 一&#xff0c;概述 偏最小二乘法是一种新型的多元统计数据分析方法&#xff0c;于1983年由S.Wold和C.Albano等人首次提出。偏最小二乘法实现了&#xff0c;在一个算法下&#xff0c;可以同时实现回归建模&#xff08;多元线…

类和对象:赋值函数

1.运算符重载 • 当运算符被⽤于类类型的对象时&#xff0c;C语⾔允许我们通过运算符重载的形式指定新的含义。C规定类类型对象使⽤运算符时&#xff0c;必须转换成调⽤对应运算符重载&#xff0c;若没有对应的运算符重载&#xff0c;则会编译报错&#xff1b;&#xff08;运算…

SwiftUI 5.0(iOS 17)滚动视图的滚动目标行为(Target Behavior)解惑和实战

概览 在 SwiftUI 的开发过程中我们常说&#xff1a;“屏幕不够&#xff0c;滚动来凑”。可见滚动视图对于超长内容的呈现有着多么秉轴持钧的重要作用。 这不&#xff0c;从 SwiftUI 5.0&#xff08;iOS 17&#xff09;开始苹果又为滚动视图增加了全新的功能。但是官方的示例可…

【LeetCode】80.删除有序数组中的重复项II

1. 题目 2. 分析 3. 代码 class Solution:def removeDuplicates(self, nums: List[int]) -> int:if len(nums) < 3:return len(nums)i 0j 1k 2while(k < len(nums)):if (nums[i] nums[j]):while(k < len(nums) and nums[j] nums[k] ):k1if (k < len(nums…

C语言指针超详解——最终篇一

C语言指针系列文章目录 入门篇 强化篇 进阶篇 最终篇一 文章目录 C语言指针系列文章目录1. 回调函数是什么2. qsort 函数2.1 概念2.2 qsort 排序 int 类型数据2.3 使用 qsort 排序结构体数据 3. 模拟实现 qsort 函数4. sizeof 与 strlen 的对比4.1 sizeof4.2 strlen4.3 sizeof…

ctf中php反序列化汇总

序列化与反序列化的概念 序列化就是将对象转换成字符串。字符串包括 属性名 属性值 属性类型和该对象对应的类名。 反序列化则相反将字符串重新恢复成对象。 对象的序列化利于对象的保存和传输,也可以让多个文件共享对象。 序列化举例&#xff1a;一般ctf题目中我们就是要将对…

02设置burpsuite代理

在日常工作之中&#xff0c;我们最常用的web客服端就是web浏览器&#xff0c;我们可以通过代理的设置&#xff0c;做到web浏览器的流量拦截&#xff0c;并且经过burpsuite代理的数据流量进行处理。 在火狐浏览器中安装foxyporxy

哥德尔不完备定理(Godel‘s Incompleteness Theorem) —— 奠定了计算机与 AI 的理论基础

哥德尔不完备定理 在数理逻辑中&#xff0c;哥德尔不完备定理是指库尔特・哥德尔于 1931 年证明并发表的两条定理。简单地说&#xff0c;第一条定理指出&#xff1a;任何相容的形式系统&#xff0c;只要蕴涵皮亚诺算术公理&#xff0c;就可以在其中构造在体系中既不能证明也不…

Java GC(垃圾回收)机制详解

Java GC&#xff08;垃圾回收&#xff09;机制详解 1、GC触发的条件2、GCRoots的对象类型 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Java的世界里&#xff0c;内存管理是自动进行的&#xff0c;其中垃圾回收&#xff08;Garbage Col…

WDL(Wide Deep Learning for Recommender Systems)——Google经典CTR预估模型

一、文章简介 Wide & Deep Learning for Recommender Systems这篇文章介绍了一种结合宽线性模型和深度神经网络的方法&#xff0c;以实现推荐系统中的记忆和泛化。这种方法在Google Play商店的应用推荐系统中进行了评估&#xff0c;展示了其显著的性能提升。 推荐系统中的…

解决使用腾讯地图没超过额度却一直报“此key每日调用量已达到上限”

1、个人开发者配额说明 2、需要在 配额管理 的 账户额度 中进行配额的分配即可。 3、开发工具接口的调用就不会出现该报错了

【专项刷题】— 快排

1、颜色分类 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 创建三个指针&#xff0c;然后把数组分为三个区域遍历代码&#xff1a; class Solution {public void swap(int[] nums, int i, int j){int t nums[i];nums[i] nums[j];nums[j] t;}public void sortCo…

如何快速开发一个简单的企业信息系统?O2OA手把手带你,高效开发!(附源码)

前言 想象一下&#xff0c;如果你的企业能够通过一个系统快速发布企业信息&#xff0c;员工们无论身在何处都能即时获取新信息&#xff0c;那该多好&#xff01;告别email轰炸和口头传达的低效&#xff0c;O2OA企业应用开发平台让这一切变得简单。 今天&#xff0c;就让我们一…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 二进制游戏(200分)- 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线…

CCF-Csp算法能力认证, 202312-2因子化简含解析

CCF-Csp算法能力认证&#xff0c; 202312-1仓库规划含解析 前言 推荐书目&#xff0c;在这里推荐那一本《算法笔记》&#xff08;胡明&#xff09;&#xff0c;需要PDF的话&#xff0c;链接如下 「链接&#xff1a;https://pan.xunlei.com/s/VNvz4BUFYqnx8kJ4BI4v1ywPA1?…