谈谈多线程中的Future
为啥会有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相关推荐
- 学习多线程中的 Future 模式一篇文章就够了 !!!
文章目录 一.Future 模式 二.Future模式的主要角色 三.Future模式的简单实现 四.JDK中的Future模式 五.Guava对Future模式的支持 一.Future 模式 Fut ...
- 阿里技术专家加多:Java异步编程实战之基于JDK中的Future实现异步编程 | 文末赠书...
正文共:14244 字 8 图 预计阅读时间: 36 分钟 本节内容摘自<Java异步编程实战>中的一小节. 一.前言 本节主要讲解如何使用JDK中的Future实现异步编程,这包含如何使 ...
- java中 immutable,future,nio
什么是Future? 用过Java并发包的朋友或许对Future (interface) 已经比较熟悉了,其实Future 本身是一种被广泛运用的并发设计模式,可在很大程度上简化需要数据流同步的并发应 ...
- 谈谈JAVA中的安全发布
谈谈JAVA中的安全发布 昨天看到一篇文章阐述技术类资料的"等级",看完之后很有共鸣.再加上最近在工作中越发觉得线程安全性的重要性和难以捉摸,又掏出了<Java并发编程实战& ...
- 多线程中 start()和run()方法的区别
多线程中 start()和run()方法的区别: Java线程一直是一个比较容易困扰的地方,首先,我们来认识下怎样生存线程. 认识 Thread 和Runnable java中实现多线程有两种途径: ...
- 阿里技术专家加多:Java异步编程实战之基于JDK中的Future实现异步编程
正文共:14244 字 8 图 预计阅读时间: 36 分钟 本节内容摘自<Java异步编程实战>中的一小节. 一.前言 本节主要讲解如何使用JDK中的Future实现异步编程,这包含如何使 ...
- 多线程中的事务回滚,你真的用对了吗?
点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/weixin_43225491/article/ details/117705686 背景介绍 1,最近有一个大数据量插入的操作 ...
- python sleep和wait_多线程中sleep()、wait()方法等的区别
1.这两个方法来自不同的类分别是Thread和Object 2.最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法. 3.wait,notify和noti ...
- 【Linux】多线程中使用fork()
(最核心的东西我在下面用红色字体标出来了,理解了那块,这些东西都是就理解了!) 在本篇文章开始之前,需要大家先了解线程和进程,这位大哥讲的言简意赅:进程和线程的主要区别(总结)_kuangsongha ...
最新文章
- JAVA 上加密算法的实现用例---转载
- mysql shell 所有表_备份mysql所有数据库的每个表的shell脚本
- 从蓝桥杯来谈Fibonacci数列
- 计算机应用问题,计算机应用的现状与发展的问题
- winCE下Unicode编码
- Perl用LWP实现GET/POST数据发送
- memcpy memmove区别和实现
- “3D几何与视觉技术”全球在线研讨会第九期~识别3D中的物体和场景
- linux目录变成只读,解决Linux文件系统变成只读的方法
- yii2之ActiveRecord 模型
- 算法引论:一种创造性方法(书)
- caffe 连接 matlab2016b
- 学习笔记:AGPS-SUPL架构
- java读取pdf的文字、图片、线条和对应坐标
- linux源代码是用,阅读Linux源代码-使用lxr和glimpse
- 各位大神,有没有类似于百度云软件开始时的设置向导的例子呀
- 【人工智能】人工智能是什么?如何入门人工智能?我们为什么要学人工智能?
- Calendar加減月份、年份-月底的处理逻辑
- java spring+mybatis整合实现爬虫之《今日头条》搞笑动态图片爬取
- SpringAMQP-Basic Queue、Work Queue、Fanout、Direct、Topic
热门文章