为啥会有Future

常见的开启线程方式有两种:

  • 重写Thread的run方法,调用start开启线程。
  • 给Thread传参Runnable实现类对象(需要实现run方法),调用start开启线程。

但是这两种方式都有局限性,那就是run方法虽然运行在子线程中,但是我们无法得知run方法执行的结果。这时又出现了几个相关类Future、FutureTask、Callable。这几个类结合Thread就可实现获取其他线程中执行方法后的返回结果。

相关简介

Future相关主要有两个类FutureTask和Callable其中Future是一个接口FutureTask是其实现类,Callable类似Runnable。这部分就谈谈如何使用以及API介绍。

首先康康怎样用

首先先来上手写法,有如下三步:

1、创建Callable实现类,实现call接口。
2、创建FutureTask实例,传参callable。
3、借助Thread执行,吧Runnable实现类传参给Thread。

        // 1、创建Callable实现类,实现call接口。val callable = object : Callable<Int> {override fun call(): Int {// 运行在子线程中val a = 1val b = 2// 模拟耗时操作SystemClock.sleep(1000)return a + b}}//2、创建FutureTask实例,传参callable。(其实FutureTask 就是Runnable的实现类)val futureTask = FutureTask(callable)// 3、借助Thread执行,Runnable实现类传参给Thread。Thread(futureTask).start()// 其他线程中可阻塞等待获取结果val result = futureTask.get()println("result:$result") // System.out: result:3

当熟悉了上面就可以这样变换了:

        // Callable 直接以Lambda 作为FutureTask构造参数。val futureTask = FutureTask {val a = 1val b = 2SystemClock.sleep(1000)a + b}Thread(futureTask).start()val result = futureTask.get()

1、看过上述的用法后我们不难发现,这个和普通开启多线程方式十分类似。二者是通过Thread构造传参Runnable 然后调用start的方式开启子线程。只是Future这里有一点区别,这里需要使用FutureTask这个Runnable实现类,这个类为系统定义好的。
2、创建FutureTask时再提供一个Callable即可,这里就是要在子线程中执行的任务。

接下来康康相关API

Future接口很简单,定义在并发包中的一个类。定义了子类需要实现的接口。


package java.util.concurrentpublic interface Future<V> {boolean cancel(boolean mayInterruptIfRunning);boolean isCancelled();boolean isDone();/*等待计算结果完成,获取计算结果。会抛出如下异常:1、CancellationException2、ExecutionException3、InterruptedException*/ V get() throws InterruptedException, ExecutionException;/*获取执行的结果,最长等待时间为timeout。可能会抛出以下异常:1、CancellationException:当计算被取消2、ExecutionException:当计算过程中threw an exception3、InterruptedException:当get等待结果时线程被打断。4、TimeoutException:get等待到最大的等待时间还未获得计算结果时。*/V get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException,TimeoutException;
}

接下来看看FutureTask 常见api:

package java.util.concurrent;
import java.util.concurrent.locks.LockSupport;public interface RunnableFuture<V> extends Runnable, Future<V> {void run();
}public class FutureTask<V> implements RunnableFuture<V> {...public FutureTask(Callable<V> callable) {if (callable == null)throw new NullPointerException();this.callable = callable;this.state = NEW;       // ensure visibility of callable}public FutureTask(Runnable runnable, V result) {this.callable = Executors.callable(runnable, result);this.state = NEW;       // ensure visibility of callable}public V get() throws InterruptedException, ExecutionException {int s = state;if (s <= COMPLETING)s = awaitDone(false, 0L);return report(s);}protected void set(V v) {if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {outcome = v;U.putOrderedInt(this, STATE, NORMAL); // final statefinishCompletion();}}
...
}

1、首先看下包,会了解到一些信息,FutureTask也是并发包下的类,并且FutureTask底层基于LockSupport来实现,这点通过get方法可以看出。
2、其次看下类的继承关系FutureTask实现了Runnable, Future接口。所以FutureTask本质也是一个Runnable实现类,只是这个实现类内部进行了自己的包装。
3、最后看下常见的api,几乎实现了Future定义的所有方法,注意下构造的使用,最常用的还是构造传Callable实现类对象。

接下来看看最后一个相关类:

很简单,就是单独定义的一个接口,供FutureTask的构造使用。

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

那么FutureTask是如何调用Callable的呢?这里就需要浅析下源码喽~

public class FutureTask<V> implements RunnableFuture<V> {···// 0、这个成员变量的值在FutureTask构造创建时被赋值。private Callable<V> callable;//Callable#call 执行的结果private Object outcome; public void run() {if (state != NEW ||!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))return;try {Callable<V> c = callable;if (c != null && state == NEW) {V result;boolean ran;try {// 1、执行Callable的call 方法,获取结果。result = c.call();ran = true;} catch (Throwable ex) {result = null;ran = false;setException(ex);}// 2、结果设置给outcomeif (ran)set(result);}} finally {// runner must be non-null until state is settled to// prevent concurrent calls to run()runner = null;// state must be re-read after nulling runner to prevent// leaked interruptsint s = state;if (s >= INTERRUPTING)handlePossibleCancellationInterrupt(s);}}protected void set(V v) {if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {// 3、结果设置给outcomeoutcome = v;U.putOrderedInt(this, STATE, NORMAL); // final statefinishCompletion();}}public V get() throws InterruptedException, ExecutionException {int s = state;if (s <= COMPLETING)//阻塞等待,内部通过LockSupport来实现。s = awaitDone(false, 0L);// 4、通过report取执行结果return report(s);}private V report(int s) throws ExecutionException {Object x = outcome;if (s == NORMAL)// 返回执行结果return (V)x;if (s >= CANCELLED)throw new CancellationException();throw new ExecutionException((Throwable)x);}
···}

可见源码乍一看还是很简单的:
1、从表面看FutureTask就是特定的Runnable类,run方法给我们写好了,run内部调用的Callable#call,这个我们自己实现。
2、从整体流程看也很好理解,这里只需知道LockSupport也是并发包下的类,借助这个类我们很好实现同步阻塞。FutureTask#set 、FutureTask#get 流程在

谈谈多线程中的Future相关推荐

  1. 学习多线程中的 Future 模式一篇文章就够了 !!!

    文章目录 一.Future 模式 二.Future模式的主要角色 三.Future模式的简单实现 四.JDK中的Future模式 五.Guava对Future模式的支持 一.Future 模式 Fut ...

  2. 阿里技术专家加多:Java异步编程实战之基于JDK中的Future实现异步编程 | 文末赠书...

    正文共:14244 字 8 图 预计阅读时间: 36 分钟 本节内容摘自<Java异步编程实战>中的一小节. 一.前言 本节主要讲解如何使用JDK中的Future实现异步编程,这包含如何使 ...

  3. java中 immutable,future,nio

    什么是Future? 用过Java并发包的朋友或许对Future (interface) 已经比较熟悉了,其实Future 本身是一种被广泛运用的并发设计模式,可在很大程度上简化需要数据流同步的并发应 ...

  4. 谈谈JAVA中的安全发布

    谈谈JAVA中的安全发布 昨天看到一篇文章阐述技术类资料的"等级",看完之后很有共鸣.再加上最近在工作中越发觉得线程安全性的重要性和难以捉摸,又掏出了<Java并发编程实战& ...

  5. 多线程中 start()和run()方法的区别

    多线程中  start()和run()方法的区别: Java线程一直是一个比较容易困扰的地方,首先,我们来认识下怎样生存线程. 认识 Thread 和Runnable java中实现多线程有两种途径: ...

  6. 阿里技术专家加多:Java异步编程实战之基于JDK中的Future实现异步编程

    正文共:14244 字 8 图 预计阅读时间: 36 分钟 本节内容摘自<Java异步编程实战>中的一小节. 一.前言 本节主要讲解如何使用JDK中的Future实现异步编程,这包含如何使 ...

  7. 多线程中的事务回滚,你真的用对了吗?

    点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/weixin_43225491/article/ details/117705686 背景介绍 1,最近有一个大数据量插入的操作 ...

  8. python sleep和wait_多线程中sleep()、wait()方法等的区别

    1.这两个方法来自不同的类分别是Thread和Object 2.最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法. 3.wait,notify和noti ...

  9. 【Linux】多线程中使用fork()

    (最核心的东西我在下面用红色字体标出来了,理解了那块,这些东西都是就理解了!) 在本篇文章开始之前,需要大家先了解线程和进程,这位大哥讲的言简意赅:进程和线程的主要区别(总结)_kuangsongha ...

最新文章

  1. JAVA 上加密算法的实现用例---转载
  2. mysql shell 所有表_备份mysql所有数据库的每个表的shell脚本
  3. 从蓝桥杯来谈Fibonacci数列
  4. 计算机应用问题,计算机应用的现状与发展的问题
  5. winCE下Unicode编码
  6. Perl用LWP实现GET/POST数据发送
  7. memcpy memmove区别和实现
  8. “3D几何与视觉技术”全球在线研讨会第九期~识别3D中的物体和场景
  9. linux目录变成只读,解决Linux文件系统变成只读的方法
  10. yii2之ActiveRecord 模型
  11. 算法引论:一种创造性方法(书)
  12. caffe 连接 matlab2016b
  13. 学习笔记:AGPS-SUPL架构
  14. java读取pdf的文字、图片、线条和对应坐标
  15. linux源代码是用,阅读Linux源代码-使用lxr和glimpse
  16. 各位大神,有没有类似于百度云软件开始时的设置向导的例子呀
  17. 【人工智能】人工智能是什么?如何入门人工智能?我们为什么要学人工智能?
  18. Calendar加減月份、年份-月底的处理逻辑
  19. java spring+mybatis整合实现爬虫之《今日头条》搞笑动态图片爬取
  20. SpringAMQP-Basic Queue、Work Queue、Fanout、Direct、Topic

热门文章

  1. Pycharm自动添加文件头注释和函数注释参数
  2. Set集合的基本使用
  3. Python print连续输出不换行
  4. 21秋期末考试个人与团队管理10257k2
  5. 网络安全笔记第四天day4(kali基本操作)
  6. JMeter参数化post请求
  7. InvocationException: GraphViz‘s executables not found【BUG已解决】
  8. Shell脚本循环语句及exit、continue和break用法
  9. BPA、BPM、BPR傻傻分不清楚?与RPA又有何关系?
  10. Errors报错记录