使用Runnable和Callable接口实现多线程的区别

先看两种实现方式的步骤:

1.实现Runnable接口

public class ThreadDemo{
public static void main(String[] args) {
for (int i = 1; i <= 5; i++) {
//创建并启动由实现Runnable接口创建的线程
new Thread(new Runner(),"Thread"+i).start();
}
}
} //实现Runnable接口
class Runner implements Runnable{
//实现run方法
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"有实现Runnable接口创建");
}
}

2.实现 Callable 接口

public class ThreadDemo{
public static void main(String[] args) throws ExecutionException, InterruptedException {
for (int i = 1; i <= 5; i++) {
//使用FutureTask保存线程结果
FutureTask<String> futureTask = new FutureTask<String>(new Caller());
//创建并启动由实现Callable创建的线程
new Thread(futureTask,"Thread"+i).start();
//获取线程执行结果
System.out.println(futureTask.get());
}
}
} //实现Callable接口
class Caller implements Callable{
//实现Call接口
@Override
public Object call() throws Exception {
String result = Thread.currentThread().getName()+"由实现Callable接口创建";
return result;
}
}

从以上代码可以看出,使用 Callable 接口创建多线程时使用了 FutureTask 进行封装,然后 FutureTask 作为参数传给 Thread 的构造函数,而 FutureTask 的作用是存放 Callable 接口 call 方法的返回值。我们来看一下 FutureTask 的源码

//FutureTask实现了RunnableFuture接口
public class FutureTask<V> implements RunnableFuture<V> {} //再看RunnableFuture接口,继承了Runnable接口
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
} //回到FutureTask,找到run方法
public void run() {
...
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
//获取call的返回值
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
...
} //看一下set方法
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
...
}
} //再看一下FutureTask的构造函数
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW;
}

从对 FutureTask 的源码分析,我们可以看出 FutureTask 实现了 Runnable 接口的 run 方法,在 run 方法中调用了 Callable 的 call 方法,将结果保存到 result 中,通过 set 方法将结果存储至 outcome 变量中。

通过以上分析,我们总结出使用 Runnable 和 Callable 接口的区别:

  1. 使用 Runnable 接口实现更加简单,而 通过 Callable 接口创建线程需要 FutureTask 进行封装;
  2. 通过实现 Runnable 接口创建的线程没有返回值,而使用 Callable 接口创建的线程可以有返回结果,并保存在 FutureTask中;
  3. 通过实现 Runnable 接口创建线程不抛出异常,而使用 Callable 接口创建的线程会抛出异常;

从以上总结可以看出,我们也可以看出 Runnable 适用于无需返回值的场景,而 Callable 接口用于需要保存返回值的场景。

使用Runnable和Callable接口实现多线程的区别的更多相关文章

  1. 使用Thread类和Runnable接口实现多线程的区别

    使用Thread类和Runnable接口实现多线程的区别 先看两种实现方式的步骤: public class ThreadDemo{ public static void main(String[] ...

  2. 通过Callable接口实现多线程

    一.通过Callable接口实现多线程 c.实现Callable重写call方法 实现Callable和实现Runnable类似,但是功能更强大,具体表现在 a.可以在任务结束后提供一个返回值,Run ...

  3. Java通过继承thread类与实现Runnable接口实现多线程的区别

    Java中线程的创建有两种方式: 1.  通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2.  通过实现Runnable接口,实例化Thread类 一.通过继承T ...

  4. Runnable和Callable接口辨析

    突然发现和启动一个线程有关的有三函数,run(), call(), start(),有点小乱,所以特别梳理一下 首先说一下start(),这个是最好说的,感觉start()和run()这俩名字是真的有 ...

  5. 关于Thread的Runnable和Callable接口

    其实非常简单:其实他们的区别就是Callable有返回值并且可以抛出异常. /** * Represents a command that can be executed. Often used to ...

  6. 实现Callable接口实现多线程

    package com.roocon.thread.t2; import java.util.concurrent.Callable; import java.util.concurrent.Exec ...

  7. callable接口的多线程实现方式

    package com.cxy.juc; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionExce ...

  8. java 多线程:Callable接口;FutureTask类实现对象【Thread、Runnable、Callable三种方式实现多线程的区别】

    Callable接口介绍: Java5开始,Java提供了Callable接口,像是Runnable接口的增强版,Callable接口提供了一个 call()方法可以作为线执行体. call()方法比 ...

  9. Java:多线程,分别用Thread、Runnable、Callable实现线程

    并发性(concurrency)和并行性(parallel)是两个概念,并行是指在同一时刻,有多条指令在多个处理器上同时执行:并发指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得宏观 ...

随机推荐

  1. AspNetCore配置多环境log4net配置文件

    前言 在之前的文章中有讲到AspNetCore多环境配置文件的应用,我们根据自己多种环境分别配置多个appsettings.$EnvironmentName.json文件. 在实际的开发中我们可能会遇 ...

  2. python基础-基本数据类型(三)

    一.散列类型 散列类型用来表示无序的集合类型 1.集合(set) Python中的集合与数学符号中的集合类似,都是用来表示无序不重复元素的集合. 1.1 集合的定义 集合使用一对{}来进行定义,集合中 ...

  3. C++基础-1-内存管理(全局区、堆区、栈区)

    1. 内存管理 1.1 全局区 1 #include<iostream> 2 using namespace std; 3 4 // 全局变量 5 int g_a = 10; 6 int ...

  4. 【总结】2022GDOI普及组试题与题解(缺两天的T4)

    标签 2022 广东省选普及组 GDOI 试题 前往Luogu下载 Luogu下载:This Day1题解 T1 邹忌讽齐王纳谏 打卡题,建议模拟 建议使用map,时间复杂度为\(O(nlogn)\) ...

  5. 面试官:ElasticSearch是什么,它有什么特性与使用场景?

    哈喽!大家好,我是小奇,一位热爱分享的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 书接上回,我本以为我跟面试我的 ...

  6. Node.js + TypeScript + ESM +HotReload ( TypeScript 类型的 Node.js 项目从 CommJS 转为 ESM 的步骤)

    当前 Node.js 版本:v16.14.0 当前 TypeScript 版本:^4.6.3 步骤 安装必要的依赖 yarn add -D typescript ts-node @tsconfig/n ...

  7. 陈胡:Apache SeaTunnel实现 非CDC数据抽取实践

    导读: 随着全球数据量的不断增长,越来越多的业务需要支撑高并发.高可用.可扩展.以及海量的数据存储,在这种情况下,适应各种场景的数据存储技术也不断的产生和发展.与此同时,各种数据库之间的同步与转化的需 ...

  8. 710. Random Pick with Blacklist - LeetCode

    Question 710. Random Pick with Blacklist Solution 题目大意:给一个N,表示一个范围[0,N),给一个黑名单列表blacklist,其中blacklis ...

  9. 项目中导入本地jar包问题

    1. 问题 一个Maven项目,需要依赖一个本地jar包,以如下方式引用: <dependency> <groupId>xxx.sdk</groupId> < ...

  10. Codeforces Round #746

    挺喜欢这场题目的 A: 水,不写了 B: Hemose Shopping 嘲讽自己一下啦~真的是caii 题意:一个数列,我们通过交换两个点(两点满足距离大于等于\(x\)),问能否排序成功. 思路: ...