Java 中使用 Callable 创建线程的方法

一、Callable 接口概述​

Callable接口位于java.util.concurrent包中,与Runnable接口类似,同样用于定义线程执行的任务,但它具有以下独特特性:​

  1. 支持返回值:Callable接口声明了一个call()方法,该方法会在任务执行完毕后返回结果,这使得我们可以在主线程中获取子线程的执行结果,方便进行后续处理。​
  1. 可抛出异常:call()方法允许抛出任何类型的异常,包括受检异常,相比Runnable接口中run()方法只能通过try-catch捕获非受检异常,Callable在异常处理上更加灵活。​

Callable接口是一个泛型函数式接口,其定义如下:

@FunctionalInterface
public interface Callable<V> {V call() throws Exception;
}

二、使用 Callable 创建线程的方法​

1. 通过 FutureTask 结合 Thread​

FutureTask类实现了RunnableFuture接口,而RunnableFuture继承了Runnable和Future接口,这使得FutureTask既可以作为Runnable被线程执行,又可以作为Future获取Callable任务的执行结果。具体使用步骤如下:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;// 定义Callable实现类
class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 1; i <= 100; i++) {sum += i;}return sum;}
}public class CallableThreadExample {public static void main(String[] args) {// 创建Callable实例Callable<Integer> callable = new MyCallable();// 创建FutureTask实例,并将Callable实例作为参数传入FutureTask<Integer> futureTask = new FutureTask<>(callable);// 创建Thread实例,并将FutureTask作为参数传入Thread thread = new Thread(futureTask);// 启动线程thread.start();try {// 获取Callable任务的执行结果Integer result = futureTask.get();System.out.println("计算结果: " + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}
}

在上述代码中,首先定义了一个实现Callable接口的MyCallable类,在call()方法中实现具体的计算逻辑,这里是计算 1 到 100 的整数和。然后在main方法中,创建Callable实例和对应的FutureTask实例,将FutureTask实例作为参数传递给Thread构造函数创建线程并启动。最后通过futureTask.get()方法获取Callable任务的执行结果,如果在获取结果过程中线程被中断或任务执行过程中抛出异常,会分别捕获InterruptedException和ExecutionException进行处理。

2. 通过 ExecutorService 线程池

import java.util.concurrent.*;class MyCallable2 implements Callable<String> {@Overridepublic String call() throws Exception {Thread.sleep(2000);return "任务执行完成";}
}public class CallableThreadPoolExample {public static void main(String[] args) {// 创建线程池ExecutorService executorService = Executors.newFixedThreadPool(3);// 创建Callable实例Callable<String> callable = new MyCallable2();// 提交Callable任务,并返回Future对象Future<String> future = executorService.submit(callable);try {// 获取任务执行结果String result = future.get();System.out.println(result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();} finally {// 关闭线程池executorService.shutdown();}}
}

在这段代码中,首先通过Executors.newFixedThreadPool(3)创建了一个固定大小为 3 的线程池executorService。接着定义了一个MyCallable2类实现Callable接口,在call()方法中让线程休眠 2 秒后返回结果。然后使用executorService.submit(callable)方法提交Callable任务,该方法会立即返回一个Future对象,通过future.get()方法获取任务的执行结果。最后在finally块中调用executorService.shutdown()方法关闭线程池,以释放资源。

三、Callable 与 Runnable 的对比​

特性​

Callable​

Runnable​

返回值​

支持返回值,通过call()方法返回任务执行结果,结果类型由泛型指定​

不支持返回值,run()方法返回值为void​

异常处理​

可以抛出任何类型的异常,包括受检异常,需要在调用端显式处理​

只能捕获非受检异常,受检异常需要在run()方法内部通过try-catch处理​

实现方式​

是一个泛型接口,需实现call()方法​

是一个普通接口,需实现run()方法​

配合使用对象​

通常与FutureTask或ExecutorService结合使用,用于获取任务执行结果​

可直接与Thread类配合使用,或提交到线程池执行​

四、总结

Callable接口为 Java 多线程编程带来了更丰富的功能和更高的灵活性,通过与FutureTask或ExecutorService线程池结合使用,我们可以方便地获取线程执行结果并进行异常处理。在实际开发中,当我们需要在多线程任务执行完毕后获取结果,或者需要更精细地处理任务执行过程中的异常时,Callable接口是一个非常好的选择。同时,合理利用线程池来管理Callable任务,能够提高程序的性能和资源利用率,让多线程程序更加高效、稳定地运行。

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

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

相关文章

2025-SMS短信验证服务或存风险,小心账号隐私“失守”

近期&#xff0c;火绒安全情报中心监测到一款伪装成具备SMS短信验证码接收服务的程序。该程序通过部署持久化后门&#xff08;即僵尸网络节点&#xff09;窃取敏感信息。火绒安全提醒广大用户务必从官方或可信渠道下载软件&#xff0c;避免因使用来路不明的程序而导致账号被盗或…

docker部署Open WebUI下载速度慢解决方法

docker pull ghcr.nju.edu.cn/open-webui/open-webui:main改成这个就可以了

气泡图、桑基图的绘制

1、气泡图 使用气泡图分析某一年中国同欧洲各国之间的贸易情况。 气泡图分析的三个维度&#xff1a; • 进口额&#xff1a;横轴 • 出口额&#xff1a;纵轴 • 进出口总额&#xff1a;气泡大小 数据来源&#xff1a;链接: 国家统计局数据 数据概览&#xff08;进出口总额&…

前端面经-VUE3篇(三)--vue Router(二)导航守卫、路由元信息、路由懒加载、动态路由

一、导航守卫 vue Router 中的 导航守卫&#xff08;Navigation Guards&#xff09; 是一个非常重要的功能&#xff0c;用于在路由切换过程中&#xff0c;拦截、控制、检查或延迟页面跳转。 你可以理解为&#xff1a; &#x1f510; “进门前的保安”&#xff0c;控制哪些页面…

MATLAB实现二氧化硅和硅光纤的单模光波特性与仿真

一.二氧化硅和硅光纤的单模光波特性 利用麦克斯方程的精确解研究二氧化硅和硅亚波长直径导线的单模光波特性。研究了单模条件、模场。 二氧化硅光纤导线是圆形截面&#xff0c;包层是空气包层&#xff0c;阶梯型变化的折射率&#xff0c;导线线径D非常小长度足够长&#xff0…

【Linux系统】第二节—基础指令(2)

hello ~ 好久不见 自己想要的快乐要自己好好争取&#xff01; 云边有个稻草人-个人主页 Linux—本篇文章所属专栏—欢迎订阅—持续更新中 目录 本节课核心指令知识点总结 本节基本指令详解 07.man 指令 08.cp 指令 09.mv 指令 10.cat 指令 11.more 指令 12.less 指令 …

为了结合后端而学习前端的学习日志——【黑洞光标特效】

前端设计专栏 今天给大家带来一个超酷的前端特效——黑洞光标&#xff01;让你的鼠标变成一个会吞噬光粒子的迷你黑洞&#xff0c;点击时还会喷射出绿色能量粒子&#xff01;&#x1f320; &#x1f680; 效果预览 想象一下&#xff1a;你的鼠标变成一个旋转的黑洞&#xff0…

[硬件电路-11]:模拟电路常见元器件 - 什么是阻抗、什么是输入阻抗、什么是输出阻抗?阻抗、输入阻抗与输出阻抗的全面解析

1. 阻抗&#xff08;Impedance&#xff09; 定义&#xff1a;阻抗是电路或元件对交流信号&#xff08;AC&#xff09;流动的阻碍能力&#xff0c;用符号Z表示&#xff0c;单位为欧姆&#xff08;Ω&#xff09;。它综合了电阻&#xff08;R&#xff09;、电感&#xff08;L&am…

机器学习和深度学习的对比

深度 数据经过深层网络后&#xff0c;语义信息表征能力强&#xff0c;对几何细节信息表征能力弱。 数据依赖性 深度学习算法需要大量的数据来训练&#xff0c;而传统的机器学习使用制定的规则。所以&#xff0c;当数据量少时&#xff0c;深度学习的性能差于机器学习&#xf…

Kubernetes 安装 minikube

安装 minikube 在 Ubuntu 上安装 minikube minikube 是一个工具&#xff0c;它可以在本地快速运行一个单节点的 Kubernetes 集群。它主要用于&#xff1a;本地学习 Kubernetes、测试和开发 Kubernetes 应用程序、快速尝试 Kubernetes 的功能。 系统配置最低要求如下 CPU&#…

【学习笔记】深度学习:典型应用

作者选择了由 Ian Goodfellow、Yoshua Bengio 和 Aaron Courville 三位大佬撰写的《Deep Learning》(人工智能领域的经典教程&#xff0c;深度学习领域研究生必读教材),开始深度学习领域学习&#xff0c;深入全面的理解深度学习的理论知识。 之前的文章参考下面的链接&#xf…

ComputeShader绘制全屏纯色纹理

参考 Getting Started With Compute Shaders In Unity 环境 Win10 Unity20194.40 全屏纯色纹理示例 使用ComputerShader逐个像素设置颜色 ComputeShader脚本 设置纹理颜色 #pragma kernel CSMainRWTexture2D<float4> Result;//纹理 half4 solidColor;//颜色[numth…

数学实验(Matlab语言环境和线性代数实验)

一、Matlab语言环境和线性代数实验 1.Matlab语言环境 Matlab简介 Matlab&#xff1a;Matrix Laboratry 矩阵实验室 Matlab 提供了强大的科学计算、灵活的程序设计流程、高质量的图形可视化与界面设计等功能&#xff0c;被广泛应用于科学计算、控制系统、信息处理等领域的分…

Android面试总结之GC算法篇

一、GC 机制核心原理与算法 面试题 1&#xff1a;Android 中为什么采用分代回收&#xff1f;分代策略如何优化 GC 效率&#xff1f; 标准答案&#xff1a; 分代回收基于对象生命周期的差异&#xff0c;将堆分为年轻代&#xff08;Young Gen&#xff09;和老年代&#xff08;Ol…

仿腾讯会议——注册登录UI

1、加载素材 2、新添加资源类 3、加载图片 4、添加左侧图片 在左侧添加一个标签 选择图片 选择图片 勾选保证图片不变形 5、修改组件名称 6、设置密码输入框 5、切换 6、编辑提示框 7、定义提交和清空的槽函数 8、设置页面标题和最先显示页面 9、清空登录信息函数实现 10、清空…

Kotlin 常见问题

以下从基础、中级、高级三个难度等级为你提供 Kotlin 面试题及参考答案&#xff1a; 基础难度 1. Kotlin 中 val 和 var 的区别是什么&#xff1f; 答案要点&#xff1a;val 用于声明不可变变量&#xff0c;类似于 Java 中的 final 变量&#xff0c;一旦赋值后就不能再重新赋…

高频数据冲击数据库的技术解析与应对方案

目录 前言一、问题现象与影响分析1.1 典型场景表现1.2 核心问题分类 二、失效根源深度剖析2.1 架构设计缺陷2.2 缓存策略缺陷 三、解决方案与最佳实践3.1 缓存架构设计3.1.1 分层缓存架构3.1.2 热点数据识别 3.2 缓存策略优化3.2.1 动态过期时间算法3.2.2 缓存更新策略对比 3.3…

[Spring] Sentinel详解

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

清除浮动的重要性及解决办法

由于父级盒子很多情况下&#xff0c;不方便给高度&#xff0c;但是子盒子浮动又不占有位置&#xff0c;最后父级盒子高度为0时&#xff0c;就会影响下面的标准流盒子。 一、为什么要清除浮动 父元素高度塌陷&#xff1a; 如果父元素内部的所有子元素都浮动了&#xff0c;并且没…

域名与官网的迷思:数字身份认证的全球困境与实践解方-优雅草卓伊凡

域名与官网的迷思&#xff1a;数字身份认证的全球困境与实践解方-优雅草卓伊凡 一、官网概念的法律与技术界定 1.1 官网的实质定义 当卓伊凡被问及”公司域名就是官网吗”这一问题时&#xff0c;他首先指出&#xff1a;”这相当于问’印着某公司logo的建筑就是该公司总部吗’…