并发编程-21J.U.C组件拓展之Future和FutureTask
文章目录
- 概述
- FutureTask的三种运行状态
- FutureTask的三种运行状态下的get/cancel操作及结果
- FutureTask的实现
- FutureTask的使用
- 示例
- Future
- FutureTask
- 代码
概述
Future接口和实现Future接口的FutureTask类,代表异步计算的结果。
FutureTask除了实现Future接口外,还实现了Runnable接口。因此,FutureTask可以交给Executor执行,也可以由调用线程直接执行(FutureTask.run()
)。
FutureTask的三种运行状态
根据FutureTask.run()方法被执行的时机,FutureTask可以处于下面3种状态
- 未启动。
FutureTask.run()
方法还没有被执行之前,FutureTask处于未启动状态。当创建一个FutureTask,且没有执行FutureTask.run()
方法之前,这个FutureTask
处于未启动状态。 - 已启动。FutureTask.run()方法被执行的过程中,FutureTask处于已启动状态。
- 已完成。FutureTask.run()方法执行完后正常结束,或被取消(
FutureTask.cancel(…
)),或执行FutureTask.run()
方法时抛出异常而异常结束,FutureTask处于已完成状态。
FutureTask的三种运行状态下的get/cancel操作及结果
当FutureTask处于未启动或已启动状态时,执行
FutureTask.get()
方法将导致调用线程阻塞当FutureTask处于已完成状态时,执行
FutureTask.get()
方法将导致调用线程立即返回结果或抛出异常当FutureTask处于未启动状态时,执行
FutureTask.cancel()
方法将导致此任务永远不会被执行当FutureTask处于已启动状态时,执行
FutureTask.cancel(true)
方法将以中断执行此任务线程的方式来试图停止任务当FutureTask处于已启动状态时,执行
FutureTask.cancel(false)
方法将不会对正在执行此任务的线程产生影响(让正在执行的任务运行完成)当FutureTask处于已完成状态时,执行
FutureTask.cancel(…)
方法将返回false。
FutureTask的实现
FutureTask的实现基于AbstractQueuedSynchronizer(AQS)。
AQS是一个同步框架,它提供通用机制来原子性管理同步状态、阻塞和唤醒线程,以及维护被阻塞线程的队列。
基于AQS实现的同步器包括:ReentrantLock
、Semaphore
、ReentrantReadWriteLock
、CountDownLatch
和FutureTask
并发编程-15并发容器(J.U.C)核心 AbstractQueuedSynchronizer 抽象队列同步器AQS介绍
每一个基于AQS实现的同步器都会包含两种类型的操作
至少一个acquire操作。这个操作阻塞调用线程,除非/直到AQS的状态允许这个线程继续执行。FutureTask的acquire操作为
get()/get(long timeout,TimeUnit unit)
方法调用至少一个release操作。这个操作改变AQS的状态,改变后的状态可允许一个或多个阻塞线程被解除阻塞。FutureTask的release操作包括
run()
方法和cancel(…)
方法
基于“复合优先于继承”的原则,FutureTask声明了一个内部私有的继承于AQS的子类Sync,对FutureTask所有公有方法的调用都会委托给这个内部子类
AQS被作为“模板方法模式”的基础类提供给FutureTask的内部子类Sync,这个内部子类只需要实现状态检查和状态更新的方法即可,这些方法将控制FutureTask的获取和释放操作。具体来说,Sync实现了AQS的tryAcquireShared(int)
方法和tryReleaseShared(int)
方法,Sync通过这两个方法来检查和更新同步状态。
FutureTask的使用
可以把FutureTask交给Executor执行
也可以通过
ExecutorService.submit(…)
方法返回一个FutureTask,然后执行FutureTask.get()
方法或FutureTask.cancel(…)
方法除此以外,还可以单独使用FutureTask
当一个线程需要等待另一个线程把某个任务执行完后它才能继续执行,此时可以使用FutureTask.
示例
Future
package com.artisan.example.aqs;import lombok.extern.slf4j.Slf4j;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;@Slf4j
public class FutureExample {static class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {// 耗时任务log.info("do something in callable start");Thread.sleep(5000);log.info("do something in callable end");return "DONE";}}public static void main(String[] args) throws Exception {// 创建一个newCachedThreadPool线程池ExecutorService executorService = Executors.newCachedThreadPool();// submit任务Future<String> future = executorService.submit(new MyCallable());// 主线程模拟一些业务操作,假设耗时一秒log.info("do something in main begin");Thread.sleep(1000);log.info("do something in main finish");// 获取刚才提交的线程MyCallable的返回结果log.info("获取MyCallable的返回结果,如果未返回,主线程将阻塞,处于等待状态");String result = future.get();log.info("result:{}", result);// 关闭线程池executorService.shutdown();}
}
观察执行结果:
FutureTask
package com.artisan.example.aqs;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;import lombok.extern.slf4j.Slf4j;@Slf4j
public class FutureTaskExample {public static void main(String[] args) throws Exception {FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {@Overridepublic String call() throws Exception {// 耗时任务log.info("do something in callable");Thread.sleep(5000);return "DONE";}});//创建一个newCachedThreadPool线程池ExecutorService executorService = Executors.newCachedThreadPool();// execute futureTask任务executorService.execute(futureTask);// 主线程模拟一些业务操作,假设耗时一秒log.info("do something in main begin");Thread.sleep(1000);log.info("do something in main finish");// 获取刚才提交的线程MyCallable的返回结果log.info("获取futureTask的返回结果,如果未返回,主线程将阻塞,处于等待状态");String result = futureTask.get();log.info("result:{}", result);// 关闭线程池executorService.shutdown();}
}
代码
https://github.com/yangshangwei/ConcurrencyMaster
并发编程-21J.U.C组件拓展之Future和FutureTask相关推荐
- 并发编程-23J.U.C组件拓展之阻塞队列BlockingQueue 和 线程池
文章目录 概述 阻塞队列的常用场景 阻塞队列的4种处理方式 JDK 7提供的7个阻塞队列 ArrayBlockingQueue LinkedBlockingQueue PriorityBlocking ...
- 并发编程-22J.U.C组件拓展之Fork/Join框架
文章目录 Fork/Join框架概述 工作窃取算法 优点 缺点 Fork/Join框架的设计 ForkJoinTask ForkJoinPool 示例 Fork/Join框架的异常处理 代码 Fork ...
- Java并发编程 - Executor,Executors,ExecutorService, CompletionServie,Future,Callable
一.Exectuor框架简介 Java从1.5版本开始,为简化多线程并发编程,引入全新的并发编程包:java.util.concurrent及其并发编程框架(Executor框架). Executor ...
- 【Java并发编程实战】(十七):Future和CompletableFuture的原理及实战——异步编程没有那么难
文章目录 引言 生活中的例子 场景1 场景2 Java中的Future 如何获取Future Future的主要方法及使用 Future的核心源码 Future模式的高阶版本-- Completabl ...
- java中同步组件_Java并发编程(自定义同步组件)
并发包结构图: 编写一个自定义同步组件来加深对同步器的理解 业务要求: * 编写一个自定义同步组件来加深对同步器的理解. * 设计一个同步工具:该工具在同一时刻,只允许至多两个线程同时访问,超过两个线 ...
- java 并发统计_java并发编程|CountDownLatch计数器
0x01,CountDownLatch介绍 CountDownLatch是一个计数器,作为java并发编程中三个组件之一,这个组件的使用频率还是很多的.这里分享下自己画的java并发编程组件的图,后面 ...
- Java并发编程有多难?这几个核心技术你掌握了吗?
本文主要内容索引 1.Java线程 2.线程模型 3.Java线程池 4.Future(各种Future) 5.Fork/Join框架 6.volatile 7.CAS(原子操作) 8.AQS(并发同 ...
- Java并发编程中的若干核心技术,向高手进阶
来源:http://www.jianshu.com/p/5f499f8212e7 引言 本文试图从一个更高的视角来总结Java语言中的并发编程内容,希望阅读完本文之后,可以收获一些内容,至少应该知道在 ...
- java 并发框架源码_某网Java并发编程高阶技术-高性能并发框架源码解析与实战(云盘下载)...
第1章 课程介绍(Java并发编程进阶课程) 什么是Disruptor?它一个高性能的异步处理框架,号称"单线程每秒可处理600W个订单"的神器,本课程目标:彻底精通一个如此优秀的 ...
最新文章
- sql2000安装时报错的问题--实例挂起和267目录名无效
- ruby gem 本地安装方法
- 史蒂夫·乔布斯很懂团队建设
- Java程序员需要掌握的计算机底层知识(三):进程、线程、纤程、中断
- c语言0x00如何不截断_数组越界及其避免方法,C语言数组越界详解
- 与计算机程序设计的文献,计算机编程语言参考文献
- php libxml安装,关于linux 安装libxml2
- python弹出窗口的代码_Python+selenium(7)-弹出窗口的代码封装,PythonSelenium,七,弹窗...
- C语言 取绝对值函数abs()使用及注意事项
- linux的内存available,Linux中available内存的计算
- 释放数据价值的真正法宝,数据要素市场化开发迫在眉睫
- Matlab中loglog函数使用
- 【ZZULIOJ】1116: 删除元素
- AOE网:关键路径和关键活动
- python微信群发itchat
- 【深度学习小知识】ROI到ROI pooling 再到ROI Align
- Pycharm添加默认头注释方法
- JMX Connectors
- 不写情书,程序员为什么还要学写作?
- 聊城大学c语言实验报告,c语言程序设计(包云)c第1章概述.ppt