老徐和阿珍的故事:Runnable和Callable有什么不同?

人物背景
老徐,男,本名徐福贵,从事Java相关研发工作多年,职场老油条,摸鱼小能手,虽然岁数不大但长的比较着急,人称老徐。据说之前炒某币败光了所有家产,甚至现在还有欠债。
阿珍,女,本名陈家珍,刚刚入职不久的实习生,虽然是职场菜鸟但聪明好学。据说是学校的四大校花之一,追求她的人从旺角排到了铜锣湾,不过至今还单身。

阿珍探出头看了看老徐的屏幕,全部都是绿色的曲线图,好奇地问:”老徐,你看的这是什么?”老徐看的太入神,转过头才发现阿珍,尬尴地笑了笑说:”我就是看看最近的行情。”老徐立马切换了窗口。

阿珍没在意又继续问到:” RunnableCallable两个接口我总搞混,这个到底有什么不同?”

面对阿珍的灵魂拷问,老徐淡定自若地说:” Runnable是用于提供多线程任务支持的核心接口, Callable是在Java 1.5中添加的 Runnable的改进版本。”

“在聊它们不同之前,我们先分别了解一下两个接口。”老徐一边说着,一边打开了源码:

Runnable接口

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

Runnable接口是一个函数式接口,它只有一个run()方法,不接受任何参数,也不返回任何值。由于方法签名没有指定 throws子句,因此无法进一步传播已检查的异常。它适用于我们不使用线程执行结果的情况,例如,异步打印日志:

package one.more;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LoggingTask implements Runnable {

    private static Logger logger = LoggerFactory.getLogger(LoggingTask.class);

    private String name;

    public LoggingTask(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        logger.info("{}说:你好!", this.name);
    }
}

在上面例中,根据 name参数把信息记录在日志文件中,没有返回值。我们可以通过 Thread启动,比如:

public static void main(String[] args) {
    String name = "万猫学社";
    Thread thread = new Thread(new LoggingTask(name));
    thread.start();;
}

我们也可以通过 ExecutorService启动,比如:

public static void main(String[] args) {
    String name = "万猫学社";
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    executorService.execute(new LoggingTask(name));
    executorService.shutdown();
}

Callable接口

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

Callable接口也是一个函数式接口,它只有一个call()方法,不接受任何参数,返回一个泛型值V,在方法签名上包含 throws Exception子句,因此我们可以很容易地进一步传播已检查异常。它适用于我们使用线程执行结果的情况,例如,异步计算阶乘:

package one.more;

import java.util.concurrent.Callable;

public class FactorialTask implements Callable<integer> {

    private int n;

    public FactorialTask(int n) {
        this.n = n;
    }

    @Override
    public Integer call() throws IllegalArgumentException {
        int fact = 1;
        if (n < 0) {
            throw new IllegalArgumentException("&#x5FC5;&#x987B;&#x5927;&#x4E8E;&#x7B49;&#x4E8E;&#x96F6;");
        }
        for (int i = n; i > 1; i--) {
            fact = fact * i;
        }
        return fact;
    }
}
</integer>

在上面例中,根据 n参数计算它的阶乘,并可以返回计算结结果。我们只能通过 ExecutorService启动,比如:

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    Future<integer> future = executorService.submit(new FactorialTask(5));
    System.out.println(future.get());
    executorService.shutdown();
}
</integer>

call()方法的结果可以通过Future对象获取到,如果在调用Future对象的get()方法时,call()方法出现了异常,异常会被继续传递,比如:

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    Future<integer> future = executorService.submit(new FactorialTask(-1));
    System.out.println(future.get());
    executorService.shutdown();
}
</integer>

抛出如下异常:

老徐和阿珍的故事:Runnable和Callable有什么不同?

老徐回头看看了阿珍,说:”这回你知道有什么不同了吧!”阿珍一头雾水地说:”信息量有点大呀,可以给我总结一下吗?””当然可以。”老徐回答。

总结

Runnable和Callable的不同:

  • Callable的任务执行后可返回值,Runnable的任务不能返回值。
  • Callable只可以通过 ExecutorService启动,Runnable可以通过 ThreadExecutorService启动。
  • Callable的call()方法可以传播已检查异常,Runnable的run()方法不可以。

最后,谢谢你这么帅,还给我 点赞关注

微信公众号:万猫学社

微信扫描二维码

关注后回复「电子书

获取12本Java必读技术书籍

Original: https://www.cnblogs.com/heihaozi/p/16049860.html
Author: 万猫学社
Title: 老徐和阿珍的故事:Runnable和Callable有什么不同?

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/580946/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • java生成机器码

    java根据系统参数生成每个计算机的唯一标识。 获取CPU序列号 /** * 获取CPU序列号 * @return * @throws IOException */ public …

    Java 2023年6月16日
    077
  • 【主流技术】Redis 在 Spring 框架中的实践

    前言 一、Redis 概述 1.1Redis 是什么? 1.2Redis 能做什么? 1.3基础知识 二、Redis 安装与基本命令 2.1Windows 安装 方式一 方式二 2…

    Java 2023年6月6日
    063
  • OpenLDAP 服务端配置(一): 基本配置

    拷贝默认配置文件并修改权限 生成配置文件中 rootpw 项的密码(注意:密码改为自己想设的密码) 修改配置文件 /etc/openldap/slapd.conf 并按如下说明修改…

    Java 2023年5月30日
    058
  • Kubernetes-Service

    1. 简介 kubernets service 是将运行一组pods上的应用程序公开为网络服务的抽象方法。 有了 kubernets service,你就无需修改应用程序即可使用服…

    Java 2023年6月7日
    079
  • EasyExcel 自定义表头,表头合并,数据合并,自定义字体背景色

    1 public void export(HttpServletResponse response, PlanExportQuery query) { 2 //查询所有数据 3 L…

    Java 2023年6月8日
    096
  • Tomcat8下的Redis会话共享

    前言: 最近在做网站的升级,从 Tomcat7升级到 Tomcat8版本,因为没接触过,就以为升级下Tomcat的版本就万事大吉,可是天不如人愿,很顺利的将应用升级到了Tomcat…

    Java 2023年6月6日
    088
  • springBoot 日志中关于profiles设置的源码解读

    在启动SpringBoot应用是看到到如下日志,于是出于好奇查看了下源代码: 首先,StartpInfoLogger类,采用jcl-over-slf4j【即Apache Commo…

    Java 2023年5月30日
    097
  • 通俗易懂spring之singleton和prototype

    关于spring bean作用域,基于不同的容器,会有所不同,如BeanFactory和ApplicationContext容器就有所不同,在本篇文章,主要讲解基于Applicat…

    Java 2023年5月30日
    092
  • m

    MyBatisPlus架构图(盗用官网的,侵,删。) SpringBoot第一个简单应用 8.编写测试类 运行结果: 常用注解 MyBatisPlus提供了一些注解供我们在实体类和…

    Java 2023年5月30日
    066
  • MySQL 服务无法启动。服务没有报告任何错误。

    版本8.0.25,今天启动发现抱错,网上搜索一下发现这样可行 启动MySQL报错: 搜索了一下,按照这样步骤解决了 1.配置一下my.ini [mysqld] basedir =&…

    Java 2023年6月13日
    098
  • 面试官:说下你对方法区演变过程和内部结构的理解

    之前我们已经了解过”运行时数据区”的程序计数器、虚拟机栈、本地方法栈和堆空间,今天我们就来了解一下最后一个模块——方法区。 简介 《Java虚拟机规范》中明…

    Java 2023年6月5日
    068
  • IDEA/Eclipse安装 Alibaba Java Coding Guidelines 插件

    Eclipse/MyEclipse 选择help >> Instakll New Software… 进入插件安装界面。 在Work with中输入: ht…

    Java 2023年5月29日
    096
  • 综合案例_创建数据库

    技术选型: web层: Servlet:前端控制器 html:视图 Filter:过滤器 BeanUtils:数据封装 jackson:json序列化工具 Service层 Jav…

    Java 2023年6月6日
    083
  • idea 个人settings和好看的主题推荐

    配置和主体搭配使用,效果最佳!!! 配置文件: 主题: Original: https://www.cnblogs.com/wyj-java/p/15744337.htmlAuth…

    Java 2023年6月15日
    0101
  • SVN 学习笔记

    概述 SVN 全称 SubVersion,是一个开放源代码的版本控制系统,它的特点是操作简单,支持跨平台操作,支持版本回退 SVN 属于 C/S 结构软件,分客户端和服务端: 服务…

    Java 2023年6月8日
    0111
  • jQuery笔记

    什么是jQuery? jQuery是一个实用的JavaScript函数库,jQuery极大地简化了JS对DOM的操作,封装并实现的一系列常用的方法。 jQuery库封装了JavaS…

    Java 2023年6月16日
    097
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球