Java-FutureTask

从Java SE 5.0开始引入了Callable和Future,通过它们构建的线程,在任务执行完成后就可以获取执行结果.

FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。另外,FutureTask还可以确保即使调用了多次run方法,它都只会执行一次Runnable或者Callable任务,或者通过cancel取消FutureTask的执行等。

//Runnable封装一个异步运行的任务,可以把它想象成为一个没有参数和返回值的异步方法。
public interface Runnable {
    public abstract void run();
}

//Callable与Runnable类似,但是有返回值。Callable接口是一个参数化的类型,只有一个方法call。
//类型参数是返回值的类型。例如,
//		Callable<Integer>表示一个最终返回Integer对象的异步计算。
public interface Callable<V> {
    V call() throws Exception;
}

//Future保存异步计算的结果。可以启动一个计算,将Future对象交给某个线程,然后忘掉它。
//Future对象的所有者在结果计算好之后就可以获得它。
//如果第一个get方法的调用被阻塞,直到计算完成。
//如果在计算完成之前,第二个get方法的调用超时,抛出一个TimeoutException异常。
//如果运行该计算的线程被中断,两个方法都将抛出InterruptedException。
//如果计算已经完成,那么get方法立即返回。
//如果计算还在进行,isDone方法返回false;如果完成了,则返回true。
//可以用cancel方法取消该计算。如果计算还没有开始,它被取消且不再开始。
//如果计算处于运行之中,那么如果mayInterrupt参数为true,它就被中断。
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;
}



public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}


//FutureTask包装器是一种非常便利的机制,同时实现了Future和Runnable接口。
public class FutureTask<V> implements RunnableFuture<V> {



}

FutureTask

FutureTask除了实现了Future接口外还实现了Runnable接口,因此FutureTask也可以直接提交给Executor执行。 当然也可以调用线程直接执行(FutureTask.run())。接下来我们根据FutureTask.run()的执行时机来分析其所处的3种状态:
(1)未启动,FutureTask.run()方法还没有被执行之前,FutureTask处于未启动状态,当创建一个FutureTask,而且没有执行FutureTask.run()方法前,这个FutureTask也处于未启动状态。
(2)已启动,FutureTask.run()被执行的过程中,FutureTask处于已启动状态。
(3)已完成,FutureTask.run()方法执行完正常结束,或者被取消或者抛出异常而结束,FutureTask都处于完成状态。

FutureTask的方法执行示意图

分析:
(1)当FutureTask处于未启动或已启动状态时,如果此时我们执行FutureTask.get()方法将导致调用线程阻塞;当FutureTask处于已完成状态时,执行FutureTask.get()方法将导致调用线程立即返回结果或者抛出异常。
(2)当FutureTask处于未启动状态时,执行FutureTask.cancel()方法将导致此任务永远不会执行。
当FutureTask处于已启动状态时,执行cancel(true)方法将以中断执行此任务线程的方式来试图停止任务,如果任务取消成功,cancel(…)返回true;但如果执行cancel(false)方法将不会对正在执行的任务线程产生影响(让线程正常执行到完成),此时cancel(…)返回false。
当任务已经完成,执行cancel(…)方法将返回false。

FutureTask的执行过程

1、创建一个futureTask对象task

2、提交task到调度器executor等待调度或者在另外一个线程中执行task

3、等待调度中…

如果此时currentThread调取执行结果task.get(),会有几种情况
if task 还没有被executor调度或正在执行中
阻塞当前线程,并加入到一个阻塞链表中waitNode
else if task 被其它Thread取消,并取消成功 或task处于中断状态
throw exception
else if task 执行完毕,返回执行结果,或执行存在异常,返回异常信息

如果此时有另外一个线程调用task.get(),执行过程同上

应用场景

  1. Future用于异步获取执行结果或者取消任务。
  2. 在高并发场景下确保任务只执行一次。

基本例子

Callable<Integer> myComputation = ...;

FutureTask<Integer> task = new FutureTask<Integer>(myComputation);

Thread t = new Thread(task);
t.start();

//...

Integer result = task.get(); //获取结果

参考:

FutureTask详解

Java多线程编程:Callable、Future和FutureTask浅析(多线程编程之四)

源码探索系列15—那个AsyncTask里面的FutureTask

AsyncTask

AsyncTask是FutureTask的一个扩展。实现流程:其构造方法中,定义了一个FutureTask以及一个Callable对象,之后执行execute()方法,在execute方法中首先调用的就是onPreExecute(),随后就执行Callable对象的call方法

doInBackground调用了,但是此时仔细想想还是在子线程中的,随后跟进postResult方法中发现handler,那就清晰了,doInBackground中的返回值(包括中间的进度更新)都会发送消息给主线程。这就是基本的实现流程,当然这里是往简单了说,不要忘记还有多个AsyncTask一起被启动的情况,不过原理也就是用了队列的方式调用了Callable对象的call方法,看到这里大家也会知道,问什么3.0之后开启多个AsyncTask的时候,它是同步执行的,也就是执行了一个之后再去执行下一个,因为它是队列的调度,不断的next.

参考:

android之Futuretask、Timer、AsyncTask的使用及原理解析

用法:

//ExecutorService
try {
    ExecutorService executor = Executors.newCachedThreadPool();
    Future<String> future = executor.submit(new Callable<String>() {
        @Override
        public String call() throws Exception {
            return "我是ExecutorService";
        }
    });
    String s = future.get();
    System.out.println("ExecutorService , s = "+s);
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
}

//new Thread
try {
    FutureTask<String> futureTask = new FutureTask<>(new Callable<String>() {
        @Override
        public String call() throws Exception {
            return "我是new Thread";
        }
    });
    new Thread(futureTask).start();
    String s = futureTask.get();
    System.out.println("new Thread , s = "+s);
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值