Runnable和Callable的区别

2023-11-15

Callable接口

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

Runnable接口

public interface Runnable {
    public abstract void run();
}

Runnable和Callable的区别

相同点

1、两者都是接口;(废话)
2、两者都可用来编写多线程程序;
3、两者都需要调用Thread.start()启动线程;

不同点

1、两者最大的不同点是:实现Callable接口的任务线程能返回执行结果;而实现Runnable接口的任务线程不能返回结果;
2、Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛;

注意点

Callable接口支持返回执行结果,此时需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取‘将来’结果;当不调用此方法时,主线程不会阻塞!

Callable工作的Demo

package com.callable.runnable;

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

/**
 * Created on 2016/5/18.
 */
public class CallableImpl implements Callable<String> {

    public CallableImpl(String acceptStr) {
        this.acceptStr = acceptStr;
    }

    private String acceptStr;

    @Override
    public String call() throws Exception {
        // 任务阻塞 1 秒
        Thread.sleep(1000);
        return this.acceptStr + " append some chars and return it!";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<String> callable = new CallableImpl("my callable test!");
        FutureTask<String> task = new FutureTask<>(callable);
        long beginTime = System.currentTimeMillis();
        // 创建线程
        new Thread(task).start();
        // 调用get()阻塞主线程,反之,线程不会阻塞
        String result = task.get();
        long endTime = System.currentTimeMillis();
        System.out.println("hello : " + result);
        System.out.println("cast : " + (endTime - beginTime) / 1000 + " second!");
    }
}

ExcutorService中的excutor和submit方法的区别

两者都是将一个线程任务添加到线程池中并执行;
1、excutor没有返回值,submit有返回值,并且返回执行结果Future对象
2、excutor不能提交Callable任务,只能提交Runnable任务,submit两者任务都可以提交
3、在submit中提交Runnable任务,会返回执行结果Future对象,但是Future调用get方法将返回null(Runnable没有返回值)

使用场景:

使用多线程任务校验被保人数据;
1、每个被保人都是一个线程任务,
2、每个线程任务执行完都需要告诉主线程执行成功还是失败
3、这里需要submit提交Callable任务返回Future对象,并通过Future.get方法来获取执行结果

FutureTask

FutureTask实现了RunnableFuture,RunnableFuture既实现了Runnbale又实现了Futrue这两个接口;它两者的结合体
FutureTask又包装了Callable(如果是Runnable最终会转化为Callable);
FutureTask可以通过Thread包装来直接执行,也可以提交给ExcutorService来执行,并可以直接通过get方法来获取执行结果;

ExecutorCompletionService

使用ExecutorCompletionService提交任务后会将执行结果放到阻塞队列中,使用take方法会得到结果,哪个任务先执行完成就先获取到这个任务的执行结果;
原理:在ExecutorCompletionService维护了一个QueueingFuture(队列任务),当通过ExecutorCompletionService提交的任务执行完成后,将结果放入QueueingFuture中;然后通过take和poll方法获取执行结果时会阻塞线程,直到当QueueingFuture中有结果时就会立即返回;
如果自己维护一个list来存放future执行结果,会导致的问题是:这样通过future.get方法来获取执行结果只能一个一个阻塞取出执行结果,如果后面的任务可能会先执行完成,后面的任务只有等待前面的任务执行完成得到结果后才能获取到结果,这样就浪费一定的时间在等待执行任务的结果上了。可以用ExecutorCompletionService来解决这个问题的。
总结:
1、自己创建一个集合来保存Future存根并循环调用其返回结果的时候,主线程并不能保证首先获得的是最先完成任务的线程返回值。它只是按加入线程池的顺序返回。因为take方法是阻塞方法,后面的任务完成了,前面的任务却没有完成,主程序就那样等待在那儿,只到前面的完成了,它才知道原来后面的也完成了。
2、使用CompletionService来维护处理线程的返回结果时,主线程总是能够拿到最先完成的任务的返回值,而不管它们加入线程池的顺序。
3、CompletionService的实现是维护了一个保存Future的BlockingQueque。只有当这个Future的任务状态是结束的时候,才会加入到这个Queque中,take()方法其实就是Producer-Consumer中的Consumer。它会从Queue中取出Future对象,如果Queue是空的,就会阻塞在那里,直到有完成的Future对象加入到Queue中。也就是先完成的必定先被取出,这样就减少了不必要的等待时间。
注意:使用Future获取多个任务的执行结果时,如果其中一个任务出现异常,就会直接中断不会获取后面任务的执行结果了,但是不会中断其他任务,其他任务会正常运行,只是结果无法获取了;如果需要中断其他任务就需要在捕获到异常后执行ExecutorService.shutdownNow方法来关闭线程,也可以通过Future.cancle方法来中断
ExecutorService中shutdownNow和shutdown的区别:
shutdownNow表示立刻关闭线程池并中断正在执行的任务;
shutdown表示线程池中的任务全部执行完成后再关闭线程池

示例代码

使用CompletionService维护结果

System.out.println("start...");
        long begin = System.currentTimeMillis();
        // 创建一个线程池
        int taskSize = 5;
        ExecutorService pool = Executors.newFixedThreadPool(taskSize);
        ExecutorCompletionService<String> completionService = new ExecutorCompletionService<String>(pool);
        try {
            for (int i = 1; i <= taskSize; i++) {
                MyCallable callable = new MyCallable(new Integer(i));
                completionService.submit(callable);
            }
            pool.shutdown();
            for (int i = 1; i <= taskSize; i++) {
                System.out.println(completionService.take().get());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 关闭线程池
        long end = System.currentTimeMillis();
        System.out.println("end..excute time:" + (end - begin) + "ms");
        return;

自己创建list维护执行结果

System.out.println("start...");
                long begin = System.currentTimeMillis();
                ExecutorService pool = null;
                try {
                    int taskSize = 5;
                    // 创建一个线程池
                    pool = Executors.newFixedThreadPool(taskSize);
                    // 创建多个返回值的任务
                    List<Future> list = Lists.newArrayList();
                    for (int i = 1; i <= taskSize; i++) {
                        MyCallable callable = new MyCallable(new Integer(i));
                        Future<String> future = pool.submit(callable);
                        list.add(future);
                        System.out.println("已添加" + i);
                    }
                    for (int i = 0; i < list.size(); i++) {
                        System.out.println(list.get(i).get().toString());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                // 关闭线程池
                pool.shutdown();
                long end = System.currentTimeMillis();
                System.out.println("end..excute time:" + (end - begin) / 1000 + "s");
                return;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Runnable和Callable的区别 的相关文章

  • 如何将变量的全部内容发送/导出到文本文件/xml 文件/剪贴板?

    我想将实例的内容 最好以树形形式 发送给某人 打印屏幕是不行的 因为类太复杂了 您需要将输出转回实例吗 在这种情况下 其他答案都是正确的 如果您只想手动检查实例的内容 理想情况下您的类都将实现toString 你可以将其重定向到一个文件 如
  • 单元测试组合服务方法

    我正在为一个类编写 junit 单元测试 该类使用以下方法实现公开的接口 public Set
  • 使用 JSch 分别为各个提示提供输入

    问题是 SSH 连接需要在常规登录后提供另一个用户 ID 和密码信息 我正在使用 JSch 连接到远程服务器 它接受以下形式的输入InputStream 和这个InputStream只能通过一次 由于会话是交互式的 这会导致问题 我尝试将输
  • Android WebView文件上传

    我正在开发一个 Android 应用程序 基本上它是一个WebView和一个进度条 Facebook 的移动网站 m facebook com 已加载到WebView 当我单击 选择文件 按钮上传图像时 没有任何反应 我已经尝试了所有的解决
  • 使用 JAX-WS 的 WebLogic 中没有模式导入的单个 WSDL

    如何使用 JAX WS 配置由 WebLogic 10 3 6 生成的 Web 服务 以将对象架构包含在单个 WSDL 文件声明 而不是导入声明 中 示例代码 界面 import javax ejb Local Local public i
  • 当 JMS Prod 位于辅助 POJO 类中时,如何在事务中包含 JMS Producer

    简短的问题 有没有办法强制无状态 EJB 调用的 POJO 存在于 EJB 的上下文中 以便事务和资源注入可以在 POJO 中工作 具体来说 在我想要做的事情的上下文中 如何在 EJB 的事务中包含 POJO JMS 生产者 该生产者在调用
  • 正则表达式在 Velocity 模板中不起作用

    我在 Test java 中尝试过这个 String regex lt s br s s gt String test1 lt br gt System out println test replaceAll regex 但是当我在速度模板
  • Java 中的 ExecuteUpdate sql 语句不起作用

    我正在学习如何将 SQL 与 Java 结合使用 我已成功安装 JDBC 驱动程序 并且能够从数据库读取记录并将其打印在屏幕上 我的问题发生在尝试执行更新或插入语句时 没有任何反应 这是我的代码 问题所在的方法 public static
  • 将现有 eclipse 项目导出到 war 文件时出现“模块名称无效”

    我正在尝试将现有 Eclipse 项目导出到 war 文件 但无论我在 WAR Export 对话框页面中输入什么 系统总是返回 模块名称无效 我不知道如何解决这个问题 谢谢您的帮助 我有同样的问题 我修复了它 请按照以下步骤操作 您可以创
  • 多线程——更快的方法?

    我有一堂有吸气剂的课程getInt 和一个二传手setInt 在某个领域 比如说领域 Integer Int 一个类的一个对象 比如说SomeClass The setInt 这里是同步的 getInt isn t 我正在更新的值Int来自
  • java swing:向 JTree 项目添加自定义图形按钮

    我想在 JTree 中的项目右侧添加一个带有小图标的附加按钮 这可以做到吗 如果是这样 怎么办 thanks Clamp 你在这方面成功了吗 我想做同样的事情 但很难让 JButton 响应用户 设置渲染器以显示按钮的过程很顺利 但所有鼠标
  • JAXB 编组器无参数默认构造函数

    我想从 java 库中编组一个 java 对象 当使用 JAXB marschaller 编组 java 对象时 我遇到了一个问题 A 类没有无参数默认构造函数 我使用Java Decompiler来检查类的实现 它是这样的 public
  • 如何检查日期字符串的有效性?

    在我的项目中 我需要检查日期字符串是否计算为正确的日期对象 我决定允许 yyyy MM dd 和日期格式 年 月 日 和 年 月 日 小时 分钟 我如何检查它们是否有效 我的代码为 1980 01 01 和一些奇怪的日期 如 3837 05
  • android 中的 java.net.URL ..新手问题

    我是java新手 正在尝试android开发 以下代码生成 malformedURLException 有人可以帮助我识别异常吗 任何提示都会非常有帮助 package com example helloandroid import and
  • 如何将库添加到 LIBGDX 项目的依赖项 gradle

    一切都在问题中 我已经尝试了在 SO 和其他网站中找到的所有答案 但没有运气 这就是我迄今为止尝试过的 adding compile fileTree dir lib include jar 到我的 build gradle adding
  • Java 中的微分方程

    我正在尝试用java创建一个简单的SIR流行病模型模拟程序 基本上 SIR 由三个微分方程组定义 S t l t S t I t l t S t g t I t R t g t I t S 易感人群 I 感染人群 R 康复人群 l t c
  • 使用自定义比较器在 Java 中创建 SortedMap

    我想创建一个TreeMap在 Java 中具有自定义排序顺序 排序后的键是字符串 需要根据第二个字符进行排序 这些值也是字符串 示例地图 Za FOO Ab Bar 您可以像这样使用自定义比较器 Comparator
  • Jackson 反序列化相当于 @JsonUnwrapped 吗?

    假设我有以下课程 public class Parent public int age JsonUnwrapped public Name name 生成 JSON age 18 first Joey last Sixpack 我如何将其反
  • java.lang.ClassCastException:com.sun.proxy.$Proxy8 无法转换为 org.openqa.selenium.internal.WrapsDriver

    我有以下切入点和 AspectJ 中给出的建议 Pointcut call org openqa selenium WebElement sendKeys public void onWebElementAction After onWeb
  • Android Google 地图无法在当前主题中找到样式“mapViewStyle”

    添加谷歌地图视图时 我扩展了MapView 使用xml编辑器将其添加到活动中 并将我的谷歌地图api密钥手动添加到布局xml文件中 我的权限在清单文件中允许互联网 我想知道的是 在 xml 编辑器中 我收到错误 无法在当前主题中找到样式 m

随机推荐

  • Latex 表格内文字过长自动换行

    法一 plain view plain copy begin tabular m 5cm 法二 plain view plain copy begin tabular p 0 9 columnwidth 法三 multirow 宏包 pla
  • 【嵌入式开源库】MultiTimer 的使用,一款可无限扩展的软件定时器

    MultiTimer 简介 下载 使用介绍 工程移植 代码分析 核心代码 实验效果 总结 简介 MultiTimer 是一个软件定时器扩展模块 可无限扩展你所需的定时器任务 取代传统的标志位判断方式 更优雅更便捷地管理程序的时间触发时序 M
  • UVA437 The Tower of Babylon

    UVA437 The Tower of Babylon 题目链接 动态规划 题目 有n n 30 种立方体 每种都有无穷多个 要求选一些立方体摞成一根尽量高的柱子 可以自行选择哪一条边作为高 使得每个立方体的底面长宽分别严格小于它下方立方体
  • OpenCV(三)——图像分割(一)

    目录 1 图像分割 2 固定阈值法 直方图双峰法 3 自动阈值法 3 1 自适应阈值法
  • AngularJs双向绑定原理

    AngularJs双向绑定 一 什么是AngularJS 二 什么是数据绑定 三 什么是双向绑定 四 双向绑定的实现 一 什么是AngularJS AngularJS是一个JavaScript框架 它诞生于2009年 由Misko Heve
  • ubuntu 20.04 安装 高版本cuda 11.7 和 cudnn最新版

    一 安装显卡驱动 参考另一篇文章 Ubuntu20 04安装Nvidia显卡驱动教程 ytusdc的博客 CSDN博客 二 安装CUDA 英伟达官网 最新版 CUDA Toolkit 12 2 Update 1 Downloads NVID
  • 在 Chrome (谷歌浏览器) 中模拟微信内置浏览器

    原文链接 在 Chrome 谷歌浏览器 中模拟微信内置浏览器 高先生的猫的博客 CSDN博客 chrome模拟微信内置浏览器 1 ios QQ 内置浏览器UA Mozilla 5 0 iPhone CPU iPhone OS 7 1 2 l
  • AndroidQ 获取、设置锁屏密码

    AndroidQ 获取 设置锁屏密码 本文中贴出的源码均为AndroidQ 9 0 源码 如果想要使用需要引入Framework的jar包 LockPatternUtils 说到密码相关的一定要提到LockPatternUtils这个类 它
  • qt中的QT的setWindowFlags的几种属性的总结

    参考博客 https www cnblogs com 132818Creator p 8194603 html 以下是大神博客的原话 setWindowFlags Qt CustomizeWindowHint 设置窗口标题栏自定义 setW
  • Tomcat源码:SocketProcessor、ConnectionHandler与Http11Processor

    前文 Tomcat源码 启动类Bootstrap与Catalina的加载 Tomcat源码 容器的生命周期管理与事件监听 Tomcat源码 StandardServer与StandardService Tomcat源码 Container接
  • I2C接口

    I2C的结构和特点 他是一具有两条总线线路 即一条串行数据线SDA和一条串行时钟线SCL 每个连接到总线上的器件都可以通过唯一的地址联系主机 它是一个真正的多主机总线 数据传输通过冲突检测和仲裁防止数据被破坏 串行的8位双向数据传输位速率更
  • 低秩分解的代码---(CODE) Low-Rank Matrix Recovery

    SAMPLE CODE Robust PCA Matrix Completion Comparison of Algorithms Robust PCA We provide MATLAB packages to solve the RPC
  • xmanager enterprise 5中文破解版下载(附产品密钥)

    xmanager 5破解版是一款功能强大的远程桌面管理软件 广泛用于各种领域的工作 包括大型工艺与半导体和服务器管理设计的IDC 互联网数据中心 大学和公司的服务器管理员与想要通过互联网连接到远程主机的个人用户是这个产品常用群体 xmana
  • centos安装后没有图形化界面

    办法 重新安装 不要选择最小模式 2 连接外网 依次执行安装指令 本人使用第二种方法已经成功 1 yum groupinstall X Window System y 2 yum groupinstall GNOME Desktop 当出现
  • LLMs开源模型们的分布式训练和量化

    前一篇博文整理了 LLMs开源模型们和数据集简介 这篇博文主要整理一下目前流行的训练方法和量化 图自Towards a Unified View of Parameter Efficient Transfer Learning Tuning
  • linux查看服务端口占用情况

    1 netstat命令 查看所有使用的端口 netstat tunlp 参数说明 参数 作用 t 指明显示TCP端口 u 指明显示UDP端口 l 仅显示监听套接字 所谓套接字就是使应用程序能够读写与收发通讯协议 protocol 与资料的程
  • PCL点云处理之批量读写点云、随机赋予颜色 并保存

    include
  • 19级计算机应用技术题库,华东师大计算机应用技术题库.doc

    华东师大计算机应用技术题库 第一章 计算机应用基础知识 一 单选题 1 一般认为 信息 information 是 C A 数据 B 人们关心的事情的消息 C 反映物质及其运动属性及特征的原始事实 D 记录下来的可鉴别的符号 2 信息资源的
  • 文件包含的漏洞、原理、利用

    最近的总结都比较简单 但不是在水 只是在我学习过程中总结的觉得真的有用的知识 还有就是有些代码发不出来我也没办法 所以就有所调整 文件包含原理是啥 文件包含漏洞 即file inclusion 意思是文件包含 是指当服务器开启allow u
  • Runnable和Callable的区别

    Runnable和Callable的区别 Callable接口 Runnable接口 Runnable和Callable的区别 相同点 不同点 注意点 Callable工作的Demo ExcutorService中的excutor和subm