06_Callable接口

news2025/1/20 20:06:13

Thread类、Runnable接口使得多线程编程简单直接。

但Thread类和Runnable接口都不允许声明检查型异常,也不能定义返回值。没有返回值这点稍微有点麻烦。不能声明抛出检查型异常则更麻烦一些。

public void run()方法规范意味着你必须捕获并处理检查型异常。即使你小心捕获异常,也不能保证这个类(Runnable对象)的所有使用者都读取异常信息。

以上两个问题现在都得到了解决。从java5开始,提供了Callable接口,是Runable接口的增强版。用Call()方法作为线程的执行体,增强了之前的run()方法。因为call方法可以有返回值,也可以声明抛出异常。

1. Callable和Runable对比

先初步认识一下Callable接口:这是一个函数式接口,因此可以用作lambda表达式或方法引用的赋值对象。

 

具体代码实现对比

class MyRunnableThread implements Runnable{
    @Override
    public void run() {

    }
}

class MyCallableThread implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        return null;
    }
}

public class CallableDemo {

    public static void main(String[] args) {
        // 创建多线程
    }
}

该如何使用Callable创建Thread对象,如果使用Runnable是:

public class CallableDemo {

    public static void main(String[] args) {
        // 创建多线程
        new Thread(new MyRunnableThread(), "threadName").start();
    }
}

现在能不能直接把MyRunnableThread换成MyCallableThread。当然不行,thread的构造方法参数需要Runnable类型的数据模型,而MyCallableThread属于Callable类型的。

那么到底怎么使用Callable创建thread对象呢?

2. Callable的使用

使用步骤:

  1. 创建Callable的实现类,并重写call()方法,该方法为线程执行体,并且该方法有返回值

  2. 创建Callable的实例。

  3. 实例化FutureTask类,参数为Callable接口实现类的对象,FutureTask封装了Callable对象call()方法的返回值

  4. 创建多线程Thread对象来启动线程,参数为FutureTask对象。

  5. 通过FutureTask类的对象的get()方法来获取线程结束后的返回值

这里出现了一个FutureTask,先认识该类,上源码:

发现:FutureTask其实充当了一个中间人的角色

/**
 * 1. 创建Callable的实现类,并重写call()方法,该方法为线程执行体,并且该方法有返回值
 */
class MyCallableThread implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName() + "执行了!");
        return 200;
    }
}

public class CallableDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 2. 创建Callable的实例,并用FutureTask类来包装Callable对象
        // 3. 创建FutureTask对象,需要一个Callable类型的参数
        FutureTask task = new FutureTask<Integer>(new MyCallableThread());
        // 4. 创建多线程,由于FutureTask的本质是Runnable的实现类,所以第一个参数可以直接使用task
        new Thread(task, "threadName").start();
        //new Thread(task, "threadName2").start();
		
        /*while (!task.isDone()) {
            System.out.println("wait...");
        }*/
        System.out.println(task.get());
        System.out.println(Thread.currentThread().getName() + " over!");
    }
}

创建方式一

//1、创建callable任务
Callable<String> c = () -> {
		Thread.sleep(3000);
		System.out.println(Thread.currentThread().getName() + " 执行了Callable任务");
		return "hehe";
};
//2、创建FutureTask(Runnable的子类)
FutureTask<String> futureTask = new FutureTask(c);
//3、创建线程传入FutureTask并启动线程
new Thread(futureTask, "ff").start();

创建方式二

FutureTask<String> f1 = new FutureTask<>(() -> {
		System.out.println("callable任务执行了");
		return "hehe:" + new Date();
});
FutureTask<String> f2 = new FutureTask<>(() -> {
		System.out.println("callable任务执行了");
		return "hehe:" + new Date();
});
new Thread(f1).start();
new Thread(f2).start();
  • FutureTask:未来的任务,用它就干一件事,异步调用。通常用它解决耗时任务,挂起堵塞问题。
  • 在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些作业交给Future对象在后台完成,当主线程将来需要时,就可以通过Future对象获得后台作业的计算结果或者执行状态。
  • 一般 FutureTask 多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。
  • FutureTask 仅在 call 方法完成时才能get结果;如果计算尚未完成,则阻塞 get 方法。
  • 一旦计算完成,就不能再重新开始或取消计算。get方法获取结果只有在计算完成时获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或者抛出异常。

注意:

  1. 为了防止主线程阻塞,建议get方法放到最后

  2. 只计算一次,FutureTask 会复用之前计算过得结果

创建多个线程,会怎样?

运行结果:依然只有一个就是threadName。

如果想打印threadName2的结果,即不想复用之前的计算结果。怎么办?再创建一个FutureTask对象即可。

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

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

相关文章

磁盘被格式化了能找到资料吗?资料找到的具体方法

磁盘格式化了还能找到&#xff0c;用读卡器接到电脑&#xff0c;就可以作为可移动磁盘来找到资料。下面讲下磁盘被格式化了能找到资料吗&#xff1f;资料找到的具体方法 磁盘被格式化了能找到资料吗&#xff1f;资料找到的具体方法 工具/软件&#xff1a;sayRecy 步骤1&#xf…

博世中国创新软件开发中心 BCSC

Bosch China Innovation and Software Development Campus 博世中国创新软件开发中心 BCSC 擎软件&#xff01; 拓未来&#xff01;Bosch China Innovation and Software Development Campus——IntroductionBOSCH——Our AdvantagesBOSCH——Hotly recruited positions Welcom…

wifi芯片行业信息汇总

1、Wifi概述 Wi-Fi这个术语被人们普遍误以为是指无线保真&#xff08;Wireless Fidelity&#xff09;&#xff0c;并且即便是Wi-Fi联盟本身也经常在新闻稿和文件中使用“Wireless Fidelity”这个词。 主要版本&#xff1a; 随着最新的 802.11 ax 标准发布&#xff0c;新的 W…

『Linux』第九讲:Linux多线程详解(一)_ 线程概念 | 线程控制之线程创建 | 虚拟地址到物理地址的转换

「前言」文章是关于Linux多线程方面的知识&#xff0c;讲解会比较细&#xff0c;下面开始&#xff01; 「归属专栏」Linux系统编程 「笔者」枫叶先生(fy) 「座右铭」前行路上修真我 「枫叶先生有点文青病」 「每篇一句」 我与春风皆过客&#xff0c; 你携秋水揽星河。 ——网络…

高精度延时

在使用STM32的时候可以使用SYSTICK来实现高精度延时。 I.MX6U没有SYSTICK定时器&#xff0c;但是有GPT定时器来实现高精度延时。 GPT&#xff08;General Purpose Timer&#xff09; GPT定时器是一个32位向上定时器&#xff08;也就是从0x00000000开始向上递增计数&#xff0…

C#【必备技能篇】制作NuGet程序包,并发布到NuGet官网

文章目录 一、准备工作&#xff1a;在NuGet上创建并获取API Keys1、首先需要登录&#xff0c;直接用微软账户登录即可2、点击右上角菜单API Keys&#xff0c;创建Key3、填写信息并创建4、复制API Key 二、制作一个简单的dll三、创建发布文件夹四、上传NuGet程序包并发布1、方法…

java 上传压缩包遍历内容

项目环境&#xff1a;Spring Boot 2.0.6.RELEASE <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.6.RELEASE</version><relativePath/> <!-- loo…

Linux安装部署 seata server 1.4.2

Linux安装部署 seata server 1.4.2 下载安装包上传至服务器 1.首先从GitHub拉取seata压缩包 https://github.com/seata/seata/releases/download/v1.4.2/seata-server-1.4.2.zip 下载到本地后上传至服务器 或使用命令拉取 wget https://github.com/seata/seata/release…

数据库系统-故障恢复

文章目录 一、数据库故障恢复思路1.1 故障类型 影响1.1.1 DMBS运行方式1.1.2 故障类型 1.2 故障恢复1.2.1 数据库故障恢复1.2.2 事务故障恢复1.2.3 系统故障恢复1.2.4 介质故障恢复 二、运行日志及其检查点2.1 DB Log2.1.1 事务的操作2.1.2 缓冲区处理策略 2.2 日志记录 三、三…

Binder与 四大组件工作原理 Service、BroadCastReceiver、ContentProvider

Service 工作原理 Service有两套流程&#xff0c;一套是启动流程&#xff0c;另一套是绑定流程。我们做App开发的同学都应该知道 1&#xff09;在新进程启动Service 我们先看Service启动过程&#xff0c;假设要启动的Service是在一个新的进程中&#xff0c;分为5个阶段&#…

农业信息化有哪些SCI期刊推荐? - 易智编译EaseEditing

以下是一些农业信息化领域的SCI期刊推荐&#xff1a; Computers and Electronics in Agriculture&#xff1a; 该期刊涵盖了计算机和电子技术在农业生产和食品生产中的应用&#xff0c;如精准农业、农业机械自动化、智能传感器、农业模型和模拟等方面的研究。 影响因子为4.5…

离散数学组合计数

基本的组合计数公式 主要内容 加法法则和乘法法则排列与组合二项式定理与组合恒等式多项式定理 加法法则和乘法法则 加法法则乘法法则分类处理与分步处理 问题1&#xff1a;某旅游团从南京到上海&#xff0c;可以乘骑车&#xff0c;也可以乘火车&#xff0c;假定骑车每日有…

PHP源码的加密方法分享

关于PHP PHP是一种易于学习和使用的服务器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的WEB站点。 PHP是能让你生成动态网页的工具之一。PHP网页文件被当作一般HTML网页文件来处理并且在编辑时你可以用编辑HTML的常规方法编写PHP。 有些时候,我们需要对P…

流程图拖拽视觉编程-流程编辑器

目录 一、简介 二、流程编辑器-视图实现 三、参考资料 一、简介 前期文章&#xff1a; 流程图拖拽视觉编程--概述_Jason~shen的博客-CSDN博客 本期内容&#xff1a; 本期将介绍流程编辑器模块的实现方法&#xff0c;效果图如下所示。该模块基于QT Graphics/View实现&…

AVL 树(自平衡二叉搜索树) 介绍

AVL 树&#xff08;自平衡二叉搜索树) 介绍 前言 在介绍二叉搜索树的章节中提到&#xff0c;二叉搜索树可能退化为线性链表&#xff0c;失去作为二叉树的各种优势。那么过程中需要维持二叉树的形式&#xff0c;同时左右子树的深度差异可控&#xff0c;如果能实现这两个条件&a…

要强的董经贵,与跳不出两轮电动车品质“陷阱”的雅迪

文|智能相对论 作者|陈明涛 “雅迪缺乏一个明确的战略定位&#xff0c;整个企业都没有方向&#xff0c;直接导致雅迪在前期竞争中失去先机。” “行业主要竞争对手更擅长销售和价格战&#xff0c;雅迪一直疲于应付、资源消耗大&#xff0c;结果也不理想。” “团队和经销商…

weblogic 反序列化 (CVE-2020-2551)漏洞复现(vulfocus)

漏洞简介 weblogic 反序列化 &#xff08;CVE-2020-2551&#xff09;漏洞是基于IIOP协议执行远程代码进行利用。 启动服务 http://192.168.5.128:10710/console/login/LoginForm.jsp 首先打开此连接&#xff0c;初始化weblogic服务。 准备工具 exp-自己写一个即可. javac…

企业编码生成系统--Python基础项目(4)

1. 成品展示&#x1f697;&#x1f680;&#x1f6eb; 运行&#x1f680;&#x1f680;&#x1f680;&#xff1a;1.在PyCharm中运行《企业编码生成系统》即可进入如图1所示的系统主界面。2.在该界面中可以选择要使用功能对应的菜单进行不同的操作。3.在选择功能菜单时&#x…

搭建electron-vue

electron-vue 准备工作修改package.jsonappveyor.yml.travis.yml.gitignore.eslintrc.js.eslintignore.babelrcsrc/renderer/main.jssrc/renderer/App.vuesrc/renderer/store/index.jssrc/renderer/store/modules/Counter.jssrc/renderer/store/modules/Counter.jssrc/renderer…

GT928 TP驱动跟读及虚拟按键上报解析

目前公司TP常用一套代码。MTK 平台使用.ko形式加载&#xff0c;所以跟读一下加深理解。 static struct i2c_driver tpd_i2c_driver {.driver {.of_match_table of_match_ptr(gt9xx_dt_match),},.probe tpd_i2c_probe,.remove tpd_i2c_remove,.detect tpd_i2c_detect,.dr…