并发编程之Callable、Runnable、Future与FutureTask

目录

  • 前言
  • 一、Callable与Runnable
    • 1.1 Callable
    • 1.2 Runnable
    • 1.3 二者对比
  • 二、Future与FutureTask
    • 2.1 Future
    • 2.2 FutureTask
    • 2.3 二者对比
  • 三、综合使用
    • 3.1 Callable执行+Future获取结果
    • 3.2 Callable执行任务+FutureTask获取执行结果
  • 四、应用场景


前言

在 Java 中,Callable、Future 和 FutureTask 是用于实现多线程编程和异步任务处理的重要接口和类。

一、Callable与Runnable

1.1 Callable

@FunctionalInterface
public interface Callable<V> {/*** Computes a result, or throws an exception if unable to do so.** @return computed result* @throws Exception if unable to compute a result*/V call() throws Exception;
}

注解是函数式接口,意味着可以用lambda表达式更简洁地使用它。Callable是个泛型接口,只有一个方法call,方法的返回类型是传递进来的V类型。call方法还支持抛出异常。

1.2 Runnable

@FunctionalInterface
public interface Runnable {/*** When an object implementing interface <code>Runnable</code> is used* to create a thread, starting the thread causes the object's* <code>run</code> method to be called in that separately executing* thread.* <p>* The general contract of the method <code>run</code> is that it may* take any action whatsoever.** @see     java.lang.Thread#run()*/public abstract void run();
}

和Callable非常相似,同样是函数式接口,只有一个方法run,没有返回类型。

1.3 二者对比

  • 返回结果
    Callable 接口中的 call() 方法可以返回结果,并且可以抛出受检异常。这使得 Callable 更适合于需要返回结果的任务。
    Runnable 接口的 run() 方法没有返回值,只能通过外部变量或其他方式来传递任务执行的结果。
  • 异常处理
    Callable 接口的 call() 方法可以抛出受检异常,而 Runnable 接口的 run() 方法只能捕获异常并在方法内部处理。
    这使得 Callable 在处理异常时更加灵活,可以通过 throws 关键字声明受检异常。
  • 线程池提交
    Callable 接口通常与 ExecutorService 结合使用,可以通过 ExecutorService.submit() 方法提交 Callable 任务,并获取返回的 Future 对象来获取结果。
    Runnable 接口也可以通过 ExecutorService 提交任务,但无法直接获取任务执行的结果,需要通过其他方式来实现结果的传递和处理。
  • 适用场景
    Callable 适用于需要返回结果、处理异常以及更复杂任务逻辑的场景,例如需要执行计算、查询数据库等操作。
    Runnable 适用于简单的并发任务,不需要返回结果或处理异常的场景,例如执行简单的耗时操作或更新 UI 界面等。

关于线程池提交这一点,看一下ExecutorService的submit()相关重载方法:

首先ExecutorService 继承自Executor,而Executor是一个接口,Executor 接口定义了一个 execute() 方法,用于执行给定的任务(即 Runnable 对象)。该方法没有返回值,只是负责接收一个 Runnable 任务,并在将来的某个时间执行该任务。

public interface ExecutorService extends Executor {
public interface Executor {/*** Executes the given command at some time in the future.  The command* may execute in a new thread, in a pooled thread, or in the calling* thread, at the discretion of the {@code Executor} implementation.** @param command the runnable task* @throws RejectedExecutionException if this task cannot be* accepted for execution* @throws NullPointerException if command is null*/void execute(Runnable command);
}
    <T> Future<T> submit(Callable<T> task);<T> Future<T> submit(Runnable task, T result);Future<?> submit(Runnable task);
  • submit(Callable<T> task)
    这个方法接收一个 Callable 对象作为参数,表示需要执行的任务,并返回一个 Future 对象。
    Callable 接口的泛型类型 T 表示任务执行完毕后的返回结果类型。
    返回的 Future 对象可以用于获取任务执行的结果,可以通过 Future.get() 方法来获取任务执行的结果,该方法会阻塞直到任务执行完毕并返回结果。
  • submit(Runnable task, T result)
    这个方法接收一个 Runnable 对象和一个泛型类型 T 的参数作为任务和结果,并返回一个 Future 对象。
    该方法会执行给定的 Runnable 任务,并将结果作为参数传递给 Future 对象。
    返回的 Future 对象可以用于获取任务执行的状态,但无法获取具体的结果。如果需要获取结果,可以调用 Future.get() 方法,但只能获取到传入的结果对象。
  • submit(Runnable task)
    这个方法接收一个 Runnable 对象作为参数,表示需要执行的任务,并返回一个 Future 对象。
    由于 Runnable 接口的 run() 方法没有返回值,因此这种情况下返回的 Future 对象的类型是 Future<?>,表示无法确定任务的返回结果类型。
    返回的 Future 对象可以用于获取任务执行的状态,但无法获取具体的结果。

submit()重载方法,都返回了Future,但是只有参数为Callable类型的方法返回的Future结果最完整, 接下来看一下Future


二、Future与FutureTask

2.1 Future

Future是一个接口,对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果等操作。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果

public interface Future<V> {boolean cancel(boolean mayInterruptIfRunning);boolean isCancelled();boolean isDone();V get() throws InterruptedException, ExecutionException;V get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutException;
}
  • cancel(boolean mayInterruptIfRunning)
    cancel() 方法用于尝试取消任务的执行。如果任务已经完成、已经被取消或者由于其他原因无法取消,则此方法返回 false。
    参数 mayInterruptIfRunning 表示是否应该中断正在执行的任务。如果任务已经开始执行并且被中断,则返回 true;否则返回 false。
  • isCancelled()
    isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
  • isDone()
    isDone() 方法用于检查任务是否已经完成。如果任务已经完成(无论是正常完成、被取消还是由于异常完成),则返回 true;否则返回 false。
  • get() throws InterruptedException, ExecutionException:
    get() 方法用于获取任务的执行结果。如果任务已经完成,则立即返回结果;如果任务尚未完成,则会阻塞当前线程直到任务完成。
    如果任务被取消,会抛出 CancellationException 异常;如果任务执行过程中出现异常,会抛出 ExecutionException 异常;如果在等待过程中当前线程被中断,会抛出 InterruptedException 异常。
  • get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException:
    get(long timeout, TimeUnit unit) 方法与 get() 方法类似,但增加了超时参数,指定最长等待时间。
    如果在指定的超时时间内任务完成,则返回结果;如果超时仍未完成,则抛出 TimeoutException 异常。
    其他异常情况与 get() 方法相同,可能抛出 InterruptedException 和 ExecutionException 异常。

2.2 FutureTask

FutureTask类实现了RunnableFuture接口,我们看一下RunnableFuture接口的实现:

public class FutureTask<V> implements RunnableFuture<V> {

RunnableFuture继承了Runnable接口和Future接口,而FutureTask实现了RunnableFuture接口。所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。

public interface RunnableFuture<V> extends Runnable, Future<V> {/*** Sets this Future to the result of its computation* unless it has been cancelled.*/void run();
}

看一下FutureTask的构造函数

    public FutureTask(Callable<V> callable) {if (callable == null)throw new NullPointerException();this.callable = callable;this.state = NEW;       // ensure visibility of callable}public FutureTask(Runnable runnable, V result) {this.callable = Executors.callable(runnable, result);this.state = NEW;       // ensure visibility of callable}

Runnable注入会被Executors.callable()函数转换为Callable类型,即FutureTask最终都是执行Callable类型的任务。

    public static <T> Callable<T> callable(Runnable task, T result) {if (task == null)throw new NullPointerException();return new RunnableAdapter<T>(task, result);}
    private static final class RunnableAdapter<T> implements Callable<T> {private final Runnable task;private final T result;RunnableAdapter(Runnable task, T result) {this.task = task;this.result = result;}public T call() {task.run();return result;}public String toString() {return super.toString() + "[Wrapped task = " + task + "]";}}

总结一下FutureTask
FutureTask是Future接口的一个唯一实现类。
FutureTask继承了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecutorService来执行。
FutureTask实现了Future,可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。

2.3 二者对比

  • 接口类型
    Future 是一个接口,用于表示一个异步计算的结果,可以通过它来获取任务的执行状态和结果。
    FutureTask 是一个实现了 Future 接口的具体类,同时也实现了 Runnable 接口,可以作为一个可执行的任务提交给 ExecutorService 执行。
  • 功能
    Future 接口主要用于获取异步任务的执行状态和结果,可以取消任务、检查任务是否完成,并获取任务的返回结果。
    FutureTask 类是一个可执行的任务,可以被提交给 ExecutorService 执行,并且可以通过 Future 接口来获取任务的执行状态和结果。
  • 用法
    Future 通常用于提交 Callable 任务后返回一个 Future 对象,通过该对象可以获取任务的执行状态和结果。
    FutureTask 可以直接作为一个任务提交给 ExecutorService,也可以手动创建并执行。FutureTask 可以包装 Callable 或 Runnable 任务,并提供更多的控制和状态查询功能。
  • 状态管理
    Future 接口提供了一种轻量级的异步计算结果的管理机制,但无法手动触发任务的执行。
    FutureTask 类提供了更多的状态管理功能,可以手动触发任务的执行、取消任务的执行,并且可以获取任务的执行状态和结果。

总的来说,Future 接口是用于管理异步任务的结果和状态的轻量级接口,而 FutureTask 类是一个具体的实现类,提供了更多的功能和灵活性,可以作为一个可执行的任务提交给 ExecutorService 执行。


三、综合使用

3.1 Callable执行+Future获取结果

 public static void test1() {ExecutorService executor = Executors.newSingleThreadExecutor();Callable<Integer> task = new Callable<Integer>() {@Overridepublic Integer call() throws Exception {// 模拟一个耗时的计算任务Thread.sleep(2000);return 42;}};Future<Integer> future = executor.submit(task);System.out.println("Task submitted");try {// 获取任务的执行结果,会阻塞当前线程直到任务完成int result = future.get();System.out.println("Task result: " + result);} catch (Exception e) {e.printStackTrace();}executor.shutdown();}

在这里插入图片描述

3.2 Callable执行任务+FutureTask获取执行结果

 public static void test2() {Callable<Integer> task = new Callable<Integer>() {@Overridepublic Integer call() throws Exception {// 模拟一个耗时的计算任务Thread.sleep(2000);return 42;}};FutureTask<Integer> futureTask = new FutureTask<>(task);Thread thread = new Thread(futureTask);thread.start();System.out.println("Task submitted");try {// 获取任务的执行结果,会阻塞当前线程直到任务完成int result = futureTask.get();System.out.println("Task result: " + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}

在这里插入图片描述

四、应用场景

讲了半天,了解一下它的应用场景吧

  • 异步任务执行:FutureTask 可以用来执行异步任务,通过 Callable 接口创建任务并提交给 FutureTask,在需要的时候获取任务的执行结果。
  • 并发任务控制:FutureTask 可以用来控制多个并发任务的执行顺序和结果获取。可以通过多个 FutureTask 对象来管理多个任务,实现任务的并发执行和结果的收集。
  • 超时处理:Future 接口提供了 get 方法的重载版本,可以传入超时时间,用于控制任务的执行时间,避免任务执行时间过长导致程序阻塞。
  • 结果缓存:可以将任务的执行结果缓存起来,避免重复执行相同的任务。FutureTask 可以用来缓存任务的执行结果,当需要结果时先检查缓存,如果缓存中有结果则直接返回,否则执行任务并缓存结果。
  • 多线程协作:FutureTask 可以用来实现多个线程之间的协作。一个线程执行任务,另一个线程等待获取任务执行结果,通过 FutureTask 可以很方便地实现线程之间的通信和协作。

在这里插入图片描述

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

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

相关文章

小明SEO:网站域名被投诉怎么恢复呢?分享

小明SEO对他的网站进行了分析&#xff0c;发现网站上存在大量非法内容&#xff0c;比如股票、金融、外汇等&#xff0c;甚至还有虚假宣传来吸引其他网站的流量。 随后他检查了该网站的tdk设置&#xff0c;尤其是网站标题&#xff0c;发现也存在违规行为。 这就是网站域名被投诉…

React Native 应用打包

引言 在将React Native应用上架至App Store时&#xff0c;除了通常的上架流程外&#xff0c;还需考虑一些额外的优化策略。本文将介绍如何通过配置App Transport Security、Release Scheme和启动屏优化技巧来提升React Native应用的上架质量和用户体验。 配置 App Transport…

Python 构建项目工具库之pybuilder使用详解

概要 在Python项目开发中,良好的构建和自动化流程是非常重要的。PyBuilder是一个用于构建Python项目的工具,它提供了简单易用的方式来定义和管理项目的构建过程,包括依赖管理、测试、代码质量检查等。本文将深入探讨PyBuilder库的使用方法、功能特性以及如何利用它来构建优…

SQL映射文件

一、SQL映射的xml文件 1.1 mapper元素 二、select 三、别名与Java映射 四、resultMap 啊

一道很有意思的题目(考初始化)

这题很有意思&#xff0c;需要你对初始化够了解才能解出来 &#xff0c;现在我们来看一下吧。 这题通过分析得出考的是初始化。关于初始化有以下知识点 &#xff08;取自继承与多态&#xff08;继承部分&#xff09;这文章中&#xff09; 所以根据上方那段知识点可知&#xf…

Linux/Backdoor

Backdoor Enumeration nmap 第一次扫描发现系统对外开放了22&#xff0c;80和1337端口&#xff0c;端口详细信息如下 22端口对应的是ssh服务&#xff0c;80端口使用Apache&#xff0c;title上写着backdoor&#xff0c;而且可以看出使用了wordpress&#xff0c;1337端口暂时还…

HyperWorks2023 下载地址及安装教程

HyperWorks是一套由Altair Engineering开发的集成化仿真平台。这个平台涵盖了许多不同领域的仿真和优化应用&#xff0c;包括结构分析、流体力学、多体动力学、优化、电磁场分析等。 HyperWorks提供了一系列强大的工具和模块&#xff0c;用于进行复杂的工程仿真和优化任务。它…

数据结构 之 队列习题 力扣oj(附加思路版)

优先级队列 #include<queue> --队列 和 优先级队列的头文件 优先级队列&#xff1a; 堆结构 最大堆 和 最小堆 相关函数&#xff1a; front() 获取第一个元素 back() 获取最后一个元素 push() 放入元素 pop() 弹出第一个元素 size() 计算队列中元素…

简单了解synchronized

什么是synchronized synchronized是Java提供的一个关键字&#xff0c;用于方法或者代码块&#xff0c;保证并发安全。 synchronized使用场景 同步代码块&#xff08;原子性&#xff09; synchronized可以用在方法上&#xff0c;或者用在代码块。 可锁的对象可以是普通对象…

【ZZULI数据结构实验一】多项式的三则运算

【ZZULI数据结构实验一】多项式的四则运算 ♋ 结构设计♋ 方法声明♋ 方法实现&#x1f407; 定义一个多项式类型并初始化---CreateDataList&#x1f407; 增加节点---Getnewnode&#x1f407; 打印多项式类型的数据-- PrintPoly&#x1f407; 单链表的尾插--Listpush_back&…

C++ 优先级与结合性

运算优先级和结合性 表达式有多种运算符混合使用时&#xff0c;求解表达式的值&#xff0c;首先要解决各种运算符的运算优先次序问题。即&#xff0c;优先级和结合性。 例如&#xff1a;下面表达式的值取决于5种运算符的优先次序。 优先级是指不同级别运算符之间的运算次序&am…

卡行领航家用户端是怎么拼团怎么挣钱的?

#领航家代理政策/怎么代理/奖金制度/双2.0模式# 全国V&#xff1a;ok1234vip 领航家用户端&#xff1a;0.52费率 一次拼团0.44费率 两次拼团0.36费率 三次拼团0.2费率 ………… 十次拼团&#xff0c;客户每月挣20480 领航家代理端&#xff1a;无押激活返现高达166/台 分润万5-万…

vue 中实现下载后端返回的流式数据

验证是否是blob /*** Event 验证是否为blob格式* */export async function blobValidate(data) {try {const text await data.text();JSON.parse(text);return false;} catch (error) {return true;}}get请求 /*** Event: get请求下载后端返回的数据流* description: url[Stri…

Flutter 旋转动画 线性变化的旋转动画

直接上代码 图片自己添加一张就好了 import dart:math;import package:flutter/material.dart;import package:flutter/animation.dart;void main() > runApp(MyApp()); //旋转动画 class MyApp extends StatelessWidget {overrideWidget build(BuildContext context) {re…

ESCTF-逆向赛题WP

ESCTF_reverse题解 逆吧腻吧babypybabypolyreeasy_rere1你是个好孩子完结撒花 Q_W_Q 逆吧腻吧 下载副本后无壳&#xff0c;直接拖入ida分析分析函数逻辑&#xff1a;ida打开如下&#xff1a;提取出全局变量res的数据后&#xff0c;编写异或脚本进行解密&#xff1a; a[0xBF, …

Spring Task 知识点详解、案例、源代码解析

简介&#xff1a;Spring Task 定时任务   所谓定时任务。就是依据我们设定的时间定时运行任务&#xff0c;就像定时发邮件一样&#xff0c;设定时间到了。邮件就会自己主动发送。 在Spring大行其道的今天&#xff0c;Spring也提供了其定时任务功能&#xff0c;Spring Task。同…

3.3 数据定义 数据库与系统概论

目录 3.3.1 模式的定义与删除 1. 定义模式 2. 删除模式 CASCADE&#xff08;级联&#xff09; RESTRICT&#xff08;限制&#xff09; 3.3.2 基本表的定义、删除与修改 表的定义 2.数据类型 3. 模式与表 4. 修改基本表 5. 删除基本表 3.3.3 索引的建立与删除 1. …

力扣刷题44-46(力扣0062/0152/0198)

62. 不同路径 题目描述&#xff1a; 一个机器人位于一个 m x n 网格的左上角 &#xff0c;机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角。问总共有多少条不同的路径&#xff1f; 思路&#xff1a; 其实就是问(0,0)->(m-1,n-1)一共有几条路。 第一个…

突破限制:亚信安慧AntDB高速处理能力的解密

AntDB不仅仅是一款优秀的数据库管理系统&#xff0c;更是一套提供丰富数据分析和处理工具的集合&#xff0c;它为用户提供了更多可能性&#xff0c;帮助他们深入理解数据、挖掘数据背后的价值。在当今信息爆炸的时代&#xff0c;数据已经成为企业决策的重要支撑&#xff0c;而A…

QT_day4:对话框

1、完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如果账号和密码不匹配&…