Future 用法详解

前言

其他知识点

Java 多线程基础
深入理解aqs
ReentrantLock用法详解
深入理解信号量Semaphore
深入理解并发三大特性
并发编程之深入理解CAS
深入理解CountDownLatch
Java 线程池

为什么出现Future机制

常见的两种创建线程的方式。一种是直接继承Thread,另外一种就是实现Runnable接口。

这两种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果。

从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果。

Future模式的核心思想是能够让主线程将原来需要同步等待的这段时间用来做其他的事情。

因为可以异步获得执行结果,所以不用一直同步等待去获得执行结果。

Future 用法详解

用法很简单

     System.out.println(" main start ");FutureTask<Integer> integerFutureTask = new FutureTask<>(new TestA());new Thread(integerFutureTask).start();System.out.println("  integerFutureTask ...");Integer integer = integerFutureTask.get();System.out.println(integer);System.out.println(" main end ");class TestA implements Callable<Integer>{@Overridepublic Integer call() throws Exception {System.out.println(" call start ");Thread.sleep(10000);System.out.println(" call end ");return 1;}
}

get时候会一直阻塞获取

当然也可以设置超时时间

public V get(long timeout, TimeUnit unit)

Future 简单原理

使用起来很简单,具体原理我们来研究一下

我们都知道Thread只能运行Runable接口

那返回值是怎么返回的呢?

FutureTask<Integer> integerFutureTask = new FutureTask<>(new TestA());此行代码可以看到FutureTask实现了 RunnableFuture接口


继续看RunnableFuture接口继承了我们的Runnable接口 还继承了一个 Future接口

Future接口
定义了返回值的一些方法

public interface Future<V> {//取消boolean cancel(boolean mayInterruptIfRunning);//是否取消boolean isCancelled();//是否执行boolean isDone();// 获取V get() throws InterruptedException, ExecutionException;//超时获取V get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutException;
}

原理流程如下

第一步

初始化任务,设置线程状态

我们可以看到线程几个状态以及从开始到结束的一些状态

outcome 是输出的返回值
runner 表示正在运行的线程
waiters 表示正在等待的线程

第二步

run方法运行

    public void run() {//判断是否在运行 if (state != NEW ||!UNSAFE.compareAndSwapObject(this, runnerOffset,null, Thread.currentThread()))return;try {//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)//c.call() 运行结束后,设置结果 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);}}

设置结果将线程状态设置,同时设置值 outcome

第三部
get 获取结果


可以看到当状态没有大于等于 COMPLETING 会阻塞

private int awaitDone(boolean timed, long nanos)throws InterruptedException {final long deadline = timed ? System.nanoTime() + nanos : 0L;WaitNode q = null;boolean queued = false;for (;;) {//如果线程被打断 if (Thread.interrupted()) {//等待队列里移除removeWaiter(q);throw new InterruptedException();}int s = state;//执行完成if (s > COMPLETING) {if (q != null)q.thread = null;return s;}else if (s == COMPLETING) // cannot time out yet//交出cpu执行权 再竞争Thread.yield();else if (q == null)q = new WaitNode();else if (!queued)//下一个线程 唤醒queued = UNSAFE.compareAndSwapObject(this, waitersOffset,q.next = waiters, q);else if (timed) {//超时nanos = deadline - System.nanoTime();if (nanos <= 0L) {removeWaiter(q);return state;}LockSupport.parkNanos(this, nanos);}elseLockSupport.park(this);}}

返回值 强转类型

线程池返回原理

提交有参数返回任务

提交代码

也是交给 FutureTask 去执行

自定义返回任务值

可以参考这个实现自己的提交

获取数据接口

public interface Future<T> {T get() throws InterruptedException;
}

做事情接口

public interface FutureTask<T> {T call();
}

异步提交处理任务

public class FutureTaskService {/*** 异步提交处理任务* @param futureTask* @param <T>* @return*/public <T> Future<T> submit(final FutureTask<T> futureTask){//异步返回AysFutureTask<T> aysFutureTask = new AysFutureTask();//线程处理任务new Thread(()->{//执行任务T call = futureTask.call();//执行完任务 通知返回aysFutureTask.done(call);}).start();//异步返回return aysFutureTask;}}

测试

public class MainTest {public static void main(String[] args) throws InterruptedException {FutureTaskService futureTaskService = new FutureTaskService();Future<String> submit = futureTaskService.submit(() -> {//提交任务return doThing();});System.out.println(" -------- 返回 -------   ");System.out.println(" --------- 做其他事情 -----   ");System.out.println(" --------- do other  -----   ");//获取 刚才提交的任务System.out.println(submit.get());}/*** 模拟数据库读写 或者 网络请求* @return*/private static String doThing(){try {Thread.sleep(5_000);} catch (InterruptedException e) {e.printStackTrace();}return " 做事情...";}
}

测试结果


可以看到我们先提交的任务,前面其他事情处理完后之后再获取结果,这期间这个任务就在执行,同一时间执行多个任务,在最后的时刻阻塞获取结果。

最后

FutureTask是Future的具体实现。

FutureTask实现了RunnableFuture接口。RunnableFuture接口又同时继承了Future 和 Runnable 接口。

Thread 可以提交 FutureTask 实际是执行 call方法
然后使用cas比较线程状态等待获取结果

Future继承图

当然 Future 还有其他扩展用法,如 CompletableFuture等

Future 用法详解相关推荐

  1. jQuery 表单验证插件,jQuery Validation Engine用法详解

    jQuery 表单验证插件,jQuery Validation Engine用法详解 功能强大的 jQuery 表单验证插件,适用于日常的 E-mail.电话号码.网址等验证及 Ajax 验证,除自身 ...

  2. python argv 详解_Python3 sys.argv[ ]用法详解

    sys.argv[]说白了就是一个从程序外部获取参数的桥梁,这个"外部"很关键,因为我们从外部取得的参数可以是多个,所以获得的是一个列表(list),也就是说sys.argv其实可 ...

  3. oracle中的exists 和 not exists 用法详解

    from:http://blog.sina.com.cn/s/blog_601d1ce30100cyrb.html oracle中的exists 和 not exists 用法详解 (2009-05- ...

  4. ROW_NUMBER() OVER()函数用法详解 (分组排序 例子多)

    ROW_NUMBER() OVER()函数用法详解 (分组排序 例子多) https://blog.csdn.net/qq_25221835/article/details/82762416 post ...

  5. python的继承用法_【后端开发】python中继承有什么用法?python继承的用法详解

    本篇文章给大家带来的内容是关于python中继承有什么用法?python继承的用法详解,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 面向对象三大特征 1.封装:根据职责将属性和方法 ...

  6. C++中substr()函数用法详解

    C++中substr()函数用法详解 原型: string substr (size_t pos = 0, size_t len = npos) const; 返回一个新构造的string对象,其值初 ...

  7. php theme_path,PHP_Yii2主题(Theme)用法详解,本文实例讲述了Yii2主题(Theme) - phpStudy

    Yii2主题(Theme)用法详解 本文实例讲述了Yii2主题(Theme)用法.分享给大家供大家参考,具体如下: 首先看看主要的配置方式: 'components' => [ 'view' = ...

  8. LayoutInflater的inflate函数用法详解

    LayoutInflater的inflate函数用法详解 LayoutInflater作用是将layout的xml布局文件实例化为View类对象. 获取LayoutInflater的方法有如下三种: ...

  9. Ext.Net学习笔记22:Ext.Net Tree 用法详解

    上面的图片是一个简单的树,使用Ext.Net来创建这样的树结构非常简单,代码如下: <ext:TreePanel runat="server"><Root> ...

最新文章

  1. 79. 单词搜索(dfs)
  2. java.net.URLEncode编码 与 URLDecode解码问题
  3. vi(vim)编辑器 学习笔记
  4. 运行linux的配置,Linux系统运行级别配置
  5. .NET中获取电脑名、IP地址及用户名方法
  6. nfc读写软件 android手机,手机nfc万能读写软件
  7. Grad-CAM绘画热力图 使用教程 pycharm+anaconda 论文画图 卷积神经网络CNN Resnet
  8. Eureka高可用注册中心通过defaultZone深入理解zone和serviceUrl
  9. SUSE12系统安装
  10. 跨步电压和接触电压的区别及联系
  11. 图片加文字用什么软件?推荐这三款软件给你
  12. SSD_装了ssd后,右下角的那个安全删除硬件的标志要怎么去掉?
  13. 小程序开发需要什么步骤?步骤教程分享
  14. springmvc测试类中如何引入controller与service,request,respon
  15. 语料库数据处理个案实例(分词和分句、词频统计、排序)
  16. Redis介绍、安装、客户端
  17. 导致项目进度延误的三种常见场景及解决方案
  18. Transformer最详细的原理加代码解读
  19. 如何去理解虚拟机的概念?
  20. 手把手教你用owncloud搭建属于自己的云盘

热门文章

  1. GeniE 实用教程(三)属性
  2. 我来说说这几天经历的南宁传销!慢慢更!
  3. 计算机网络中怎么共享文件,图文教你如何设置局域网里网络邻居中的共享文件...
  4. 跨域请求实现百度搜索和360搜索的智能提示
  5. 第 338 场周赛 (力扣周赛)
  6. cadence allegro导入dxf文件
  7. 开篇回忆——为什么选择java?
  8. 高仿微信发起群聊添加联系人界面
  9. 中小型企业 CRM 系统有哪些好的推荐?
  10. PowerShell 学习笔记 - 1 PS Core 基础