FutureTask源码解析一

2021-03-11  本文已影响0人  kakukeme

FutureTask源码解析一

https://blog.csdn.net/jiangtianjiao/article/details/104029225

考虑到文章篇幅过长,分为两篇讲解
本片主要介绍FutureTask涉及的一些接口和基本知识

FutureTask简介

FutureTask是一种可取消的异步计算任务,它实现了Future接口,代表了异步任务的返回结果。从而FutureTask可以启动和取消异步计算任务、查询异步计算任务是否完成和获取异步计算任务的返回结果。只有异步计算任务结束时才能获取返回结果,当异步计算任务还未结束时调用get方法会使线程阻塞。一旦异步计算任务完成,计算任务不能重新启动或者取消,除非调用runAndReset。

FutureTask继承关系图

image-20210311194746175.png

FutureTask实现了RunnableFuture,RunnableFuture结合了Future和Runnable。

下面对上述接口进行逐个分析

①Runnable接口

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

run方法定义了线程要执行的任务,但无返回值,那么需要返回值又该怎么办? 引入callable接口,callable能返回任务的执行结果。

②Callable接口

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

相对于Runable,Callable具有返回值,可以向上抛出异常,而Runnable的run方法不能抛出异常,只能在方法内部进行catch处理。

③Future接口
Future接口用来代表一个异步操作的执行结果。我们可以用它来获取一个操作的执行结果、取消一个操作、判断一个操作是否已经完成或者是否被取消。

public interface Future<V> {
    // 该方法用来获取执行结果, 如果任务还在执行中, 就阻塞等待
    V get() throws InterruptedException, ExecutionException;
    // 该方法同get方法类似, 不同的是它最多等待指定的时间, 如果指定时间内任务没有完成, 则会抛出TimeoutException异常;
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
    // 该方法用来尝试取消一个任务的执行, 它的返回值是boolean类型, 表示取消操作是否成功.
    boolean cancel(boolean mayInterruptIfRunning);
    // 该方法用于判断任务是否被取消了。如果一个任务在正常执行完成之前被cancel掉了, 则返回true
    boolean isCancelled();
    // 如果一个任务已经结束, 则返回true
    // 任务结束包含了以下三种情况,见下面3)
    boolean isDone();
}

根据FutureTask.run()方法被执行的时机,FutureTask可以处于下面3种状态

image-20210311194824489.png

当FutureTask处于未启动或已启动状态时,执行FutureTask.get()方法将导致调用线程阻塞。
当FutureTask处于已完成状态时,执行FutureTask.get()方法将导致调用线程立即返回结果或抛出异常。
当FutureTask处于未启动状态时,执行FutureTask.cancel()方法将导致此任务永远不会被执行。
当FutureTask处于已启动状态时,执行FutureTask.cancel(true)方法将以中断执行此任务线程的方式来试图停止任务。
注意:线程中断仅仅是置线程的中断状态位,并不会停止线程,需要用户自己去监视线程的状态为并做进一步处理。
当FutureTask处于已启动状态时,执行FutureTask.cancel(false)方法将不会对正在执行此任务的线程产生影响。
注意:此时会让正在执行的任务运行完成。
当FutureTask处于已完成状态时,执行FutureTask.cancel(...)方法将返回false。

image-20210311194851363.png

④RunnableFuture 接口
RunnableFuture接口同时继承了Runable与Callable接口

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

FutureTask涉及工具类

①Executors
Executors是一个用于创建线程池的工厂类,同时提供了一些有用的静态方法,比如FutureTask中使用到的接口Executors.callable(runnable, result),此处该类不是重点,不作过多解析,只简单描述与FutureTask相关部分。

public class Executors {
    /**
     * Returns a {@link Callable} object that, when
     * called, runs the given task and returns the given result.  This
     * can be useful when applying methods requiring a
     * {@code Callable} to an otherwise resultless action.
     * @param task the task to run
     * @param result the result to return
     * @param <T> the type of the result
     * @return a callable object
     * @throws NullPointerException if task null
     */
    public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
    }
    
    /**
     * A callable that runs given task and returns given result
     */
    static final class RunnableAdapter<T> implements Callable<T> {
        final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {
            task.run();
            return result;
        }
    }
    // RunnableAdapter采用了适配器模式,将一个Runnable类型对象适配成Callable类型。
    // 对于result原样返回并无什么意义,只是适配成Callable需要返回值。
}

②Unsafe
Unsafe 是 sun.misc 包下的一个类,可以直接操作堆外内存,可以随意查看及修改JVM中运行时的数据,使Java语言拥有了类似C语言指针一样操作内存空间的能力。Unsafe 的操作粒度不是类,而是内存地址和所对应的数据,增强了Java语言操作底层资源的能力。后面单独写一篇关于Unsafe使用的文章,此处不是重点,不做解析。

上一篇下一篇

猜你喜欢

热点阅读