创建线程的第三种方式:实现Callable接口(含部分源码解析)

2023-11-01

创建线程的第三种方式——实现Callable接口

package com.lqy.Multithreading;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/*
创建线程的第三种方法:实现Callable接口
实现Callable接口是创建线程的三种方法中唯一一个带有返回值的方法
步骤:
1、实现Callable接口
2、重写里面的Call方法(注意是Call不是Run
3、创建Callable实现类的对象
4、将实现类对象作为参数传递给FutureTask构造函数
5、将FutureTask对象作为参数传递给Thread构造函数(因为FutureTask实现了Runnable接口,所以可以这么传)
6、调用Thread类的start方法
这种创建线程的方法一般用于需要很长时间的操作但是我们只需要结果的情况
比如我们需要进行一个算法运算,这个运算的过程非常繁琐,需要很长的时间才能完成,但是我们最终只需要它的运行结果而已
那么我们就可以先在要获取结果前多一段时间就运行该线程,在最终需要结果的地方去获取结果
但是注意,如果执行了获取结果的方法但是那个线程还没有得到结果的话,线程会阻塞直到执行结果出来
 */
public class CallableImpl implements Callable {
   
/*
   
在重写Call方法的时候注意
    前面的返回类型你可以自己修改,但是在创建FutureTask类的时候里面的泛型要与之相同
     */
   
@Override
   
public Object call() throws Exception {
       
System.out.println("CallableImpl");
       
return "我是Call方法的返回值";
    }

   
public static void main(String[] args) {
       
CallableImpl callable=new CallableImpl();
       
FutureTask<Object> futureTask=new FutureTask<>(callable);
       
Thread thread=new Thread(futureTask);
       
/*
       
需要注意一件事:
        FutureTask类中的get方法获取返回值只能执行一次
        而且,如果使用了这个方法但是线程还没有运行到可以返回的那行代码,那么就会一直阻塞
        比如如果我在这里执行了如下代码:
        Object result=futureTask.get();
       
那么就永远阻塞了
        当然,我更想说的是,如果你使用的是这种方法创建线程并且需要返回值的话,里面就别写死循环
        否则就是死锁在召唤
         */
       
thread.start();
       
try {
           
Object result=futureTask.get();
           
System.out.println(result);
        }
catch (InterruptedException e) {
            e.printStackTrace();
        }
catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

我们来看看Callable类

很显然,它和Runnable类一样,是个功能接口,里面也只有一个方法。

我们接下来看看FutureTask类。

通过一路的追踪源码我们可以知道:

FuterueTask extends RunnableFuture

RunnableFuture extends Runnable,Future

所以我们先来看看Future类

通过查看源码我们可以发现,Future是一个接口,其中定义的接口方法有:

 

注意,这里只是定义了这些方法,并没有实现,实现这些方法是在FutureTask类中。

接下来我们来看RunnableFuture类

可以发现,它继承了Runnable类和Future类,但是并没有实现他们(自己定义为接口,那么就可以不用实现接口的方法)。

最后来到FutureTask中,根据Java继承的特性可知,Future间接的继承了Runnable类和Future类。

也就是说FutureTask类要实现Run方法和Future类中定义的所有方法。

我们先来看看构造方法:

可以发现,它有两个构造方法:

 

我们再来看看这个类中的一些方法:

获取线程的允许情况我们可以直接通过状态码知道:

有一个颇有意思的方法:

 

我们来实验一下:

package com.lqy.Multithreading;



import java.util.concurrent.Callable;

import java.util.concurrent.FutureTask;



public class FutureTaskTest implements Callable {

    private int i=0;



    //发现了个有意思的事,它的返回值就算不写也不会报错

    @Override

    public Object call() throws Exception {

        while (true){

            System.out.println(i++);

        }

    }



    public static void main(String[] args) {

        FutureTaskTest futureTaskTest=new FutureTaskTest();

        FutureTask futureTask=new FutureTask(futureTaskTest);

        Thread thread=new Thread(futureTask);

        thread.start();

        //我们来看看cancel能不能停止该线程

        futureTask.cancel(true);

    }

}

运行结果:

 

可以发现,可以阻止线程运行。

 接下来我们来看看我们最经常用的,获取运行结果的Get方法

 

 

runAndReset方法会在线程池中使用到,等讲到线程池的时候在详细聊一聊吧。

总结的说:

三种方式:

第一种:Thread,实现了Runnable接口

第二种:Runnable,重写了本类的run方法,使用Thread类的start方法运行

第三种:Callable,重写了本类的call方法,但是作为接收参数的FutureTask间接继承了Runnable接口,其中的run方法实现是将重写的call方法放在run方法中,并加上相应的操作,最后调用Thread类的start方法。

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

创建线程的第三种方式:实现Callable接口(含部分源码解析) 的相关文章

随机推荐

  • 基础算法题——异或和之和(位运算、组合数)

    异或和之和 题目链接 解题思路 解题方案 暴力枚举 时间复杂度 O n3 超时 位操作 组合数 解铃还须系铃人 对于这种与 或 异或的位操作 一般也是通过位操作来解答 总结规律 题目要求在 n 个正整数中枚举 3 个数进行位操作 若要确定
  • Spring Boot v2.4.4源码解析(十)依赖注入原理下 —— 依赖解析

    从 Spring Boot v2 4 4源码解析 八 依赖注入原理上 由一道面试题引起的思考 Autowired和 Resource的区别 可以看出 解析待注入字段或参数主要由 org springframework beans facto
  • windows与linux字符集转换

    linux下不能显示windows下的汉字 Windows和LINUX中缺省使用的字符集不同 Windows下工具可以识别LINUX中使用的UTF8字符集 而LINUX下一般工具不会自动转换Windows下的GBK字符集 如果确实需要显示
  • Mysql数据备份及数据恢复

    数据备份概述 根据数据备份的方式 分为逻辑备份和物理备份 物理备份 物理备份就是备份数据文件了 比较形象点就是cp下数据文件 但真正备份的时候自然不是的cp这么简单 逻辑备份 将数据导出至文本文件中 mysqldump是采用SQL级别的备份
  • IDEA配置Scala,使用IDEA创建第一个Scala项目

    1 首先安装IDEA IDEA的官网 https www jetbrains com idea download section mac 选择你对应的系统 版本选择社区版即可 如果有需要的可以选择Ultimate版 2 安装后 打开IDEA
  • java常用类及其方法使用StringBuffer

    基本介绍 1 StringBuffer类是对String类的增强 其代表了可变字符序列 可以对字符串的内容进行增删 2 很多方法和String是相同的 但是StringBuffer是可变长度的 3 StringBuffer是一个容器 4 类
  • stata做计量入门常用代码一览!

    现在越来越多人有写论文的需求啦 经管领域的论文中 实证研究已成为必备操作 有了下面的代码 直接上手跑数据 一 分组回归 实证中 常常要分行业分年度 分省份分年度等分组回归 保存出回归出来的某些参数 statsby就是一个有用的命令 命令语句
  • MySQL基础——多表查询练习题

    文章目录 1 查询员工的姓名 年龄 部门信息 隐式内连接 2 查询年龄小于30岁的员工的姓名 年龄 职位 部门信息 显示内连接 3 查询拥有员工的部门id 部门名称 4 查询所有年龄大于40岁的员工 及其归属的部门名称 如果没有分配部门 也
  • 人工智能ai算法_AI算法比您想象的要脆弱得多

    人工智能ai算法 In William Gibson s 2010 novel Zero History a character preparing to go in a high stakes raid wears an oddly pa
  • window像mac一样使用快捷键(AutoHotkey、SharpKeys和PowerToys)

    自己有win和mac两台笔记本 每天都需要在两台电脑切换进行开发 快捷键的差异就让人很难受 个人喜好mac快捷键 常用的几个快捷键分布比较合理 所以网上找来了解决方案供大家参考 我想作为一名 Mac User 使用 Win 首先感到不适应的
  • ####好好好#####时序数据库介绍和使用

    1 基础 1 1 时序数据的定义 什么是时间序列数据 Time Series Data TSD 以下简称时序 从定义上来说 就是一串按时间维度索引的数据 用描述性的语言来解释什么是时序数据 简单的说 就是这类数据描述了某个被测量的主体在一个
  • webpack3 CommonsChunkPlugin插件分离三方库(jQuery.js/vue.js等)和公共模块 分别打包

    需求 使用webpack进行打包时 我们不想自己写的js文件与第三方的js库一起打包成一个庞大的文件 而是想要第三方插件库单独打包一个js 我们自己写的js独立打包 优点 1 分割js文件避免单独一个js文件太大影响用户使用体验 2 通常来
  • fastdfs特点

    FastDFS是一个开源的轻量级分布式文件系统 它对文件进行管理 功能包括 文件存储 文件同步 文件访问 文件上传 文件下载 等 解决了大容量存储和负载均衡的问题 特别适合以文件为载体的在线服务 如相册网站 视频网站等等 FastDFS为互
  • 每个开发人员都应该知道的10个CSS选择器

    对于任何网站而言 要在用户上产生良好印象是什么 是的 它是任何网站的用户界面 每个开发人员都知道为用户创建美观的设计以便与任何网站进行交互非常重要 如果你不熟悉CSS及其选择器 那么在最短的时间内巧妙地对网页进行样式设置并不是一件容易的事
  • css中display属性作用大全

    定义和用法 display 属性规定元素应该生成的框的类型 实例 设置段落生成一个行内框 p inline display inline 使用说明 说明 这个属性用于定义建立布局时元素生成的显示框类型 对于 HTML 等文档类型 如果使用
  • 学习记录,利用canvas写扫雷游戏

    记录js学习后制作的第一关小游戏 这里的代码还不够精简 许多地方偷懒没有封装 逻辑也有许多可以优化 胜利条件 找出所有地雷并标记
  • XSS-labs靶场1-13关解法答案

    目录 XSS labs克隆 下载地址 第一关 解法 第二关 解法 第三关 解法 第四关 解法 第五关 解法 第六关 解法 第七关 解法 第八关 解法 第九关 解法 第十关 解法 第十一关 解法 第十二关 解法 第十三关 解法 从XSS pa
  • 关于利用python解压文件出现文件名乱码的问题

    利用python中的zipfile模块解压zip文件会出现文件名乱码的问题 会成为莫名的字符 例如 出现原因 zipfile模块中的源代码如下 if flags 0x800 UTF 8 file names extension filena
  • C++异常详解

    文章目录 前言 一 C语言传统的处理错误的方式 二 C 异常概念 三 异常的使用 3 1 异常的抛出和捕获 3 2 异常的重新抛出 3 3 异常安全 3 4 异常规范 四 C 标准库的异常体系 五 自定义异常体系 六 异常的优缺点 C 异常
  • 创建线程的第三种方式:实现Callable接口(含部分源码解析)

    创建线程的第三种方式 实现Callable接口 package com lqy Multithreading import java util concurrent Callable import java util concurrent