一次搞懂 Runnable、Callable、Future、FutureTask,不懂不要钱!

点击上方 "编程技术圈"关注, 星标或置顶一起成长

后台回复“大礼包”有惊喜礼包!

每日英文

Make the person mature is not the time, but the experience. subway tasted, through the nature; through the world, see light the world. 

使人成熟的不是岁月,而是经历。百味尝遍,自然看透;看透世态,看淡世事。

每日掏心话

记住,不是你认为可以给予就给予。所以不要那么轻易许下承诺。记住,不是你做的不够好。所以不要悲悯的以为自己一事无成。

来自:yes的练级攻略 | 责编:乐乐

编程技术圈(ID:study_tech)第 1126 次推文

往日回顾:又有9名程序员被抓,这次真的活该!

     

   正文   

一般创建线程只有两种方式,一种是继承Thread,一种是实现Runnable接口。但是这两种创建方式有一个致命的缺点就是没有返回值,没返回值就让人很苦恼了啊。得用共享变量或者其他通信方式才能得到线程处理完的结果,就有点麻烦。

还有一般不提倡使用继承Thread来创建线程方式,因为Java只有单继承,不能继承多个。但是Runnable是接口,所以可以让你的实现类同时实现多个接口。而且之后要上线程池,如果之前你是用Runnable来实现的,那就可以直接传入Runnable给线程池进行管理了!

在Java1.5之后就有了Callable、Future。

这二种可以提供线程执行完的结果!

接下来简单介绍下Runnable、Callable 、Future、 FutureTask。

Runnable

Runnable 是一个接口,简单就一个方法,实现run方法,在run方法里面编写你要执行的代码就行了,但是没有任务返回接口,并且无法抛出异常。


简单应用


Callable

Callable也是一个接口,很简单就一个call方法,在call方法里面编写你要执行的代码就行了,返回的就是执行的结果了。和Runnable 差别就是它有返回的结果,并且可以抛出异常!一般配合ThreadPoolExecutor使用的。

简单应用,它不能直接配合Thread 使用。

Future

Future也是一个接口,它可以对具体的Runnable或者Callable任务进行取消、判断任务是否已取消、查询任务是否完成、获取任务结果。如果是Runnable的话返回的结果是null(下面会剖析为什么Runnable的任务,Future还能返回结果)。接口里面有以下几个方法。注意两个get方法都会阻塞当前调用get的线程,直到返回结果或者超时才会唤醒当前的线程。

简单应用

FutureTask

因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask。

FutureTask不是接口了,是个class。它实现了RunnableFuture接口

public class FutureTask<V> implements RunnableFuture<V>

而RunnableFuture接口又继承了Runnable和Future

public interface RunnableFuture<V> extends Runnable, Future<V>

因此它可以作为Runnable被线程执行,又可以有Future的那些操作。它的两个构造器如下

简单应用

线程池应用

一般情况我们在用多线程的时候都会上线程池,而且一般我们使用ThreadPoolExecutor来创建线程池,我的上篇文章已经讲述了ThreadPoolExecutor,这里再补充一下submit用法。

也就是说如果我们需要返回任务的执行结果我们就得调用submit方法而不是execute。

submit也不神秘就是封装了一下我们的任务再execute

newTaskFor方法是new了一个FutureTask返回。

在公众号顶级架构师后台回复“架构整洁”,获取一份惊喜礼包。

所以三个方法其实都是把task转成FutureTask,如果task是Callable,就直接赋值。如果是Runnable 就转为Callable再赋值

task是Callable的情况

task是Runnable 的情况

看了源码就揭开了神秘面纱了,就是因为Future需要返回结果,所以内部task必须是Callable,如果task是Runnable 我就造个假,偷天换日,在Runnable 外面包个Callable马甲,返回的结果在构造时就写好。

如果是调用Future<?> submit(Runnable task);提交任务,构造的时候就直接是RunnableFutureftask = newTaskFor(task, null);直接塞了个null。所以调用Future.get时,拿到的就是null。

所以这样有什么用呢?就只用能来判断任务已经执行完毕,就类似于Thread.join。

这还有个Futuresubmit(Runnable task, T result);你可能会奇怪这有啥用啊,你传入一个result,Future.get的时候返回的不还是这个result嘛。是个没错,但是这样用就行了!

这样就可以得到修改后的结果了!

总结

综上所述,知道了Runnable 和Callable 的区别,Callable 可以获得任务结果和抛出异常,Runnable 没结果没异常抛出。

Future可以很容易的获得异步执行的结果,并且对任务进行一些操控。并且get等待结果时会阻塞,所以当任务之间有依赖关系的时候,一个任务依赖另一个任务的结果,可以用Future的get来等待依赖的任务完成的结果。

FutureTask 就是具体的实现类,有Runnable 的特性又有Future的特性,内部包的是Callable ,当然也有接受Runnable 的构造器,只是会偷偷把Runnable 转成Callable 来实现能返回结果的方法。

PS:欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,欢迎转发分享给更多人。

版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢!

欢迎加入后端架构师交流群,在后台回复“学习”即可。

猜你还想看

阿里、腾讯、百度、华为、京东最新面试题汇集

Java 身份证号码识别系统

某程序员动了公司的祖传代码“屎山”,半年后怒交辞职报告!

MyBatis动态SQL,写SQL更爽

BAT等大厂Java面试经验总结

别找了,想获取 Java大厂面试题学习资料

扫下方二维码回复「手册」就好了



  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值