FutureTask

FutureTask是Future的实现,用来异步任务的获取结果,可以启动和取消异步任务,查询异步任务是否计算结束以及获取最终的异步任务的结果。通过get()方法来获取异步任务的结果,但是会阻塞当前线程直至异步任务执行结束。一旦任务执行结束,任务不能重新启动或取消,除非调用runAndReset()方法。

代码示例:

public class ThreadTest {

  public static void main(String[] args) throws Exception {

    Callable<String> myCallable = new MyCallableThread();
FutureTask<String> futureTask = new FutureTask<>(myCallable);
Thread myCallableThread = new Thread(futureTask);
myCallableThread.setName("MyThread-implements-Callable-test");
myCallableThread.start();
System.out.println("Run by Thread:" + futureTask.get()); //通过线程池执行
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit(futureTask);
executorService.shutdown();
System.out.println("Run by ExecutorService:" + futureTask.get());
}
} class MyCallableThread implements Callable<String> { @Override
public String call() throws Exception {
return Thread.currentThread().getName();
}
}

实现一个自己的FutureTask

根据FutureTask核心原理,要实现一个FutureTask必须满足以下方面:

  • 需要泛型定义用以返回结果类型
  • 需要一个callable对象,在构造方法中传入
  • 需要实现runnable接口,在run方法中实现具体结果计算
  • 需要一个公开的get方法来获取结果
  • 如果线程没有执行完,则调用get方法的线程需要进入等待队列
  • 需要一个字段记录线程执行的状态
  • 需要一个等待队列存储等待结果的线程

代码示例:

/**
* 1. 泛型定义
* 2. 构造方法 callable
* 3. 实现了runnable
* 4. get方法返回callable执行结果
* 5. get方法有阻塞的效果(未执行结束的话)
*/
public class MyFutureTask<T> implements Runnable { // 程序执行的结果
private T result; // 要执行的任务
private Callable<T> callable; // 任务运行的状态
private volatile int state = NEW; // 任务运行的状态值
private static final int NEW = 0;
private static final int RUNNING = 1;
private static final int FINISHED = 2; // 获取结果的线程等待队列
LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<>(100); // 执行当前FutureTask的线程,用CAS进行争抢
AtomicReference<Thread> runner = new AtomicReference<>(); public MyFutureTask(Callable<T> task) {
this.callable = task;
} @Override
public void run() {
// 判断当前对象的状态,如果是New且抢锁成功就执行
if (state != NEW || !runner.compareAndSet(null, Thread.currentThread())) return;
state = RUNNING;
try {
result = callable.call();
} catch (Exception e) {
e.printStackTrace();
} finally {
state = FINISHED;
} // 方法执行完,唤醒所有线程
while (true) {
Thread waiterThread = waiters.poll();
if (waiterThread == null) break;
LockSupport.unpark(waiterThread);
}
} public T get() {
// 如果状态不是FINISHED,则进入等待队列
if (state != FINISHED) {
waiters.offer(Thread.currentThread());
}
while (state != FINISHED) {
LockSupport.park();
}
return result;
}
} // MyFutureTask 测试
public class FutureTaskTest {
public static void main(String[] args) { Callable<String> myCallable = new MyCallableThread();
MyFutureTask<String> futureTask = new MyFutureTask<>(myCallable);
Thread myCallableThread = new Thread(futureTask);
myCallableThread.setName("MyFutureTask-test");
myCallableThread.start();
System.out.println("Run by Thread:" + futureTask.get());
}
} class MyCallableThread implements Callable<String> { @Override
public String call() throws Exception {
return Thread.currentThread().getName();
}
}

自定义FutureTask实现的更多相关文章

  1. Java FutureTask理解

    尊敬原创作者,转载请注明出处: http://blog.csdn.net/gemmem/article/details/8956703 FutureTask是为了弥补Thread的不足而设计的,它可以 ...

  2. [转载] java多线程学习-java.util.concurrent详解(二)Semaphore/FutureTask/Exchanger

    转载自http://janeky.iteye.com/blog/770393 ------------------------------------------------------------- ...

  3. java中Future与FutureTask使用与分析

    Future与FutureTask都是用于获取线程执行的返回结果.下面我们就对两者之间的关系与使用进行一个大致的介绍与分析 一.Future与FutureTask介绍: Future位于java.ut ...

  4. FutureTask简单实战

    FutureTask是什么? 线程池的实现核心之一是FutureTask.在提交任务时,用户实现的Callable实例task会被包装为FutureTask实例ftask:提交后任务异步执行,无需用户 ...

  5. 《java并发编程实战》读书笔记11--构建自定义的同步工具,条件队列,Condition,AQS

    第14章 构建自定义的同步工具 本章将介绍实现状态依赖性的各种选择,以及在使用平台提供的状态依赖机制时需要遵守的各项规则. 14.1 状态依赖性的管理 对于并发对象上依赖状态的方法,虽然有时候在前提条 ...

  6. Flume自定义拦截器(Interceptors)或自带拦截器时的一些经验技巧总结(图文详解)

    不多说,直接上干货! 一.自定义拦截器类型必须是:类全名$内部类名,其实就是内部类名称 如:zhouls.bigdata.MySearchAndReplaceInterceptor$Builder 二 ...

  7. SpringCache自定义过期时间及自动刷新

    背景前提 阅读说明(十分重要) 对于Cache和SpringCache原理不太清楚的朋友,可以看我之前写的文章:Springboot中的缓存Cache和CacheManager原理介绍 能关注Spri ...

  8. Java线程之FutureTask

    简述 FutureTask是Future接口的实现类,并提供了可取消的异步处理的功能,它包含了启动和取消(start and cancel)任务的方法,同时也包含了可以返回FutureTask状态(c ...

  9. 线程池续:你必须要知道的线程池submit()实现原理之FutureTask!

    前言 上一篇内容写了Java中线程池的实现原理及源码分析,说好的是实实在在的大满足,想通过一篇文章让大家对线程池有个透彻的了解,但是文章写完总觉得还缺点什么? 上篇文章只提到线程提交的execute( ...

随机推荐

  1. TPL DataFlow .Net 数据流组件,了解一下

    回顾上文 作为单体程序,依赖的第三方服务虽不多,但是2C的程序还是有不少内容可讲: 作为一个常规互联网系统,无外乎就是接受请求.处理请求,输出响应. 由于业务渐渐增长,数据处理的过程会越来越复杂和冗长 ...

  2. 再见Jenkins,从Gitlab代码提交到k8s服务持续交付只需七毛三(走过路过不要错过)

    Gitlab runner 快速搭建CICD pipeline 背景 日常开发中,相信大家已经做了很多的自动化运维环境,用的最多的想必就是利用Jenkins实现代码提交到自动化测试再到自动化打包,部署 ...

  3. DataGrid通过DataSet保存为xml文件,并导入

    做了个小的DataGrid通过DataSet保存为xml_测试,DataGrid通过DataSet保存为xml_测试,通过dataSet.writeXML()和dataSet.readXML()方法完 ...

  4. Windows10 OpenSSH 快捷设置 避免 Bad owener or permission on

    配置ssh 有两个地方 ~/.ssh/config 这个亲测失败,怎么搞都报错 bad owner .... c:/programdata/ssh/ssh_config 亲测有效 (显示隐藏文件才看的 ...

  5. svg文字描边动画

    svg动画在网页中是经常见到的,svg动画使得网页看起来清新美观 任何不规则图形都可以由svg绘制完成,当然也包括文字,文字本身就可以看作一个不规则图形

  6. python+selenium实现163邮箱登陆—iframe动态ID定位 及常用定位方法

    今天发现之前的登录163邮箱脚本定位不到iframe了,原因是iframe拼接了动态ID,修改后的脚本如下: from selenium import webdriver driver = webdr ...

  7. 利用gcc编译链接时出现 ‘undefined reference to `std::ios_base::Init::Init()’ 解决

    一般编译链接c++程序最好使用g++,若有如上的报错信息,需要在gcc后加上 -lstdc++ eg: gcc test.c -lstdc++ gcc和g++都是GNU的一个编译器. g++:后缀.c ...

  8. Java 将PDF 转为Word、图片、SVG、XPS、Html、PDF/A

    本文将介绍通过Java编程来实现PDF文档转换的方法.包括: 1. PDF转为Word 2. PDF转为图片 3. PDF转为Html 4. PDF转为SVG 4.1 将PDF每一页转为单个的SVG ...

  9. 非controller层获取response和request对象

    ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttribute ...

  10. C#多线程学习之如何操纵一个线程

    下面我们就动手来创建一个线程,使用Thread类创建线程时,只需提供线程入口即可.(线程入口使程序知道该让这个线程干什么事) 在C#中,线程入口是通过ThreadStart代理(delegate)来提 ...