使用Runnable和Callable接口实现多线程的区别
使用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 接口的区别:
- 使用 Runnable 接口实现更加简单,而 通过 Callable 接口创建线程需要 FutureTask 进行封装;
- 通过实现 Runnable 接口创建的线程没有返回值,而使用 Callable 接口创建的线程可以有返回结果,并保存在 FutureTask中;
- 通过实现 Runnable 接口创建线程不抛出异常,而使用 Callable 接口创建的线程会抛出异常;
从以上总结可以看出,我们也可以看出 Runnable 适用于无需返回值的场景,而 Callable 接口用于需要保存返回值的场景。
使用Runnable和Callable接口实现多线程的区别的更多相关文章
- 使用Thread类和Runnable接口实现多线程的区别
使用Thread类和Runnable接口实现多线程的区别 先看两种实现方式的步骤: public class ThreadDemo{ public static void main(String[] ...
- 通过Callable接口实现多线程
一.通过Callable接口实现多线程 c.实现Callable重写call方法 实现Callable和实现Runnable类似,但是功能更强大,具体表现在 a.可以在任务结束后提供一个返回值,Run ...
- Java通过继承thread类与实现Runnable接口实现多线程的区别
Java中线程的创建有两种方式: 1. 通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2. 通过实现Runnable接口,实例化Thread类 一.通过继承T ...
- Runnable和Callable接口辨析
突然发现和启动一个线程有关的有三函数,run(), call(), start(),有点小乱,所以特别梳理一下 首先说一下start(),这个是最好说的,感觉start()和run()这俩名字是真的有 ...
- 关于Thread的Runnable和Callable接口
其实非常简单:其实他们的区别就是Callable有返回值并且可以抛出异常. /** * Represents a command that can be executed. Often used to ...
- 实现Callable接口实现多线程
package com.roocon.thread.t2; import java.util.concurrent.Callable; import java.util.concurrent.Exec ...
- callable接口的多线程实现方式
package com.cxy.juc; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionExce ...
- java 多线程:Callable接口;FutureTask类实现对象【Thread、Runnable、Callable三种方式实现多线程的区别】
Callable接口介绍: Java5开始,Java提供了Callable接口,像是Runnable接口的增强版,Callable接口提供了一个 call()方法可以作为线执行体. call()方法比 ...
- Java:多线程,分别用Thread、Runnable、Callable实现线程
并发性(concurrency)和并行性(parallel)是两个概念,并行是指在同一时刻,有多条指令在多个处理器上同时执行:并发指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得宏观 ...
随机推荐
- 论文翻译:2020_TinyLSTMs: Efficient Neural Speech Enhancement for Hearing Aids
论文地址:TinyLSTMs:助听器的高效神经语音增强 音频地址:https://github.com/Bose/efficient-neural-speech-enhancement 引用格式:Fe ...
- netty系列之:netty中的核心MessageToMessage编码器
目录 简介 框架简介 MessageToMessageEncoder MessageToMessageDecoder MessageToMessageCodec 总结 简介 在netty中我们需要传递 ...
- python代码统计核酸检测结果截图
#QQ:502440275@qq.com#本截图适合安康码截图,如需其他地区截图统计,可与我QQ或QQ邮箱联系#1.在当前文件夹下创建imgs文件夹用于存放图片,图片格式.jpg#2.在当前文件夹下创 ...
- AQS源码阅读
简介 AQS 全程为 AbstractQueuedSynchronizer , 在 java.util.concurrent.locks包下的一个抽象类. 类的具体作用以及设计在开始类描述信息里面就有 ...
- Node.js躬行记(18)——半吊子的可视化搭建系统
我们组维护的管理后台会接到很多开发需求,每次新开页面,就会到处复制黏贴相关代码. 并且还会经常性的翻阅文档,先在书签或地址栏输入WIKI地址,然后找到那一份说明文档,再定位到要看的组件位置. 虽然单人 ...
- python学习-Day16
目录 今日内容详细 内置函数补充 常见内置函数 help() id() int() isinstance() pow() round() sum() 求和 迭代器 可迭代对象 什么是可迭代对象? 哪些 ...
- [笔记] $f(i)$ 为 $k$ 次多项式,$\sum_{i=0}^nf(i)\cdot q^i$ 的 $O(k\log k)$ 求法
\(f(i)\) 为 \(k\) 次多项式,\(\sum_{i=0}^nf(i)\cdot q^i\) 的 \(O(k\log k)\) 求法 令 \(S(n)=\sum_{i=0}^{n-1}f(i ...
- springboot简单发送邮件介绍
1.新建一个springboot项目 2.所需要的的jar包: <dependency> <groupId>org.springframework.boot</group ...
- srpingboot拦截器
1.创建一个普通的web工程. 2.先创建需要的基础文件,比如一个用户类. package com.example.mode; public class User { private Integer ...
- 关于win10安装wsl子系统Ubuntu图形界面的错误解决
解决了https://blog.csdn.net/weixin_30834783/article/details/102144314Xserver个人使用的是VcXsrv. 在WSL中配置环境变量DI ...