java中Future与FutureTask使用与分析

Future与FutureTask都是用于获取线程执行的返回结果。下面咱们就对二者之间的关系与使用进行一个大体的介绍与分析java

1、Future与FutureTask介绍函数

Future位于java.util.concurrent包下,它是一个接口this

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;
}

Future接口中声明了5个方法,下面介绍一下每一个方法的做用:spa

cancel方法用来取消任务,取消成功则返回true,取消失败则返回false。参数mayInterruptIfRunning设置为false,表示不容许在线程运行时中断,设置为true则表示容许。具体可分为如下三种状况:线程

        一、若是任务已经完成,则不管mayInterruptIfRunning为true仍是false,都返回false,这是由于你要取消的任务已经完成,则认为取消任务失败;code

        二、若是任务正在执行,则不管mayInterruptIfRunning为true仍是false,都返回true。只不过mayInterruptIfRunning为true时线程会被中断,false时线程不会被中断会执行完。对象

        三、若是任务尚未执行,则不管mayInterruptIfRunning为true仍是false,都返回true。blog

isCancelled方法用于判断任务是否被取消成功,cancel方法成功则返回 true,反之则为false。继承

isDone用于判断任务是否完成,  若是任务完成则返回true。任务完成包括正常结束、任务被取消、任务发生异常,都返回true接口

get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;

get(long timeout, TimeUnit unit)用来获取执行结果,若是在指定时间内,还没获取到结果,抛出 java.util.concurrent.TimeoutException 异常 

FutureTask 实现了RunnableFuture接口,而RunnableFuture则继承了Future<V>与Runnable接口,因此 FutureTask不只实现了 Future<V>接口的全部方法,还具备本身的run方法,咱们能够看下它的类图

、Future与FutureTask使用与分析

一、使用Future时,咱们须要实现Callable接口,并经过ExecutorService接口的submit方法获取返回的Future对象,

二、使用FutureTask时,根据FutureTask的构造函数能够看到FutureTask既能够接收Callable的实现类,也能够接收Runnable的实现类。当你传入的是Callable的实现类时,能够获取线程执行的结果;传入Runnable的实现类时,因为Runnable的实现没有返回值,须要传入一个你设置的线程完成标识,也就是result,而后当线程结束时会把你传入的result原值返回给你,FutureTask的构造函数具体以下:

    public class FutureTask<V> implements RunnableFuture<V>public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
     }

     public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);//runnable转化为callable 
        this.state = NEW;       // ensure visibility of callable
     }
}

 接下来咱们看下Future与FutureTask具体的使用代码:

        // 执行任务 实现Runnable
        FutureTaskJobRunnable taskRun = new FutureTaskJobRunnable();
        // 执行任务 实现Callable
        FutureTaskJobCallable taskCall = new FutureTaskJobCallable();
        String val = "ok";
        // 线程运行成功后把,返回你传入的val值
        FutureTask<String> futureTaskRun = new FutureTask<String>(taskRun, val);
        // 线程运行,返回线程执行的结果
        FutureTask<String> futureTaskCall = new FutureTask<String>(taskCall);
        
        //声明线程池
        ExecutorService executor = Executors.newCachedThreadPool();        
        //Future
        Future<String> future =  executor.submit(taskCall);
        System.out.println(future.get());
        //FutureTask
        executor.submit(futureTaskCall);
        System.out.println(futureTaskCall.get());
        //FutureTask自定义线程执行
        new Thread(futureTaskRun).start();
        System.out.println(futureTaskRun.get());
public class FutureTaskJobCallable implements Callable<String>{
    
    public String call() throws Exception {
        System.out.println("FutureTaskJobCallable已经执行了哦");
        Thread.sleep(1000);
        return "返回结果";
    }

}

public class FutureTaskJobRunnable implements Runnable {
    
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("FutureTaskJobRunnable已经执行了哦");
    }

}

根据上面的代码咱们从ExecutorService接口中submit方法入手,看下AbstractExecutorService类对submit方法的具体实现。

    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }

    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }


    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }

能够看到当你使用submit方法提交任务时,都会经过newTaskFor方法转换成FutureTask对象,因此咱们具体分析下上面代码中的三种状况:

一、若是你传入的是本身实现的Runaable类或者Callable类,那么sumbit方法天然会帮你自动封装为FutureTask对象,运行后经过Future对象获取结果。

二、你传入的已是个本身构造的FutureTask对象,因为FutureTask实际上是实现了Runnable接口的,它自己就是个Runaable实现类, sumbit方法仍是会将它视为Runnable类来进行封装,并最终会执行FutureTask本身的run方法,一系列实现都在你传入的FutureTask对象内完成,因此你能够直接经过本身构建的FutureTask获取结果;

三、本身单独声明线程运行,跟第2点相似,FutureTask自己就是个Runnabel实现类,天然能够作为参数传入Thread运行;

那么咱们把自定义的Runnable、Callable实现类作为参数构造FutureTask后,FuttureTask是如何运行的呢,咱们能够看下FuttureTask中具体的代码实现

//你传入的Runnable与Callable实现类都会在构造函数中转化为Callable
private Callable<V> callable;

    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 {
                    result = c.call();//运行后返回结果
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    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 interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

能够看到FutureTask类自己的run方法,就是执行Runnable、Callable的实现类并获取返回结果的过程。

因此ExecutorService接口中submit方法归根结底仍是要把你传入的对象封装成FutureTask对象,并经过FutureTask类的内部实现来获取结果的,返回的Future接口对象也要依赖于FutureTask实例化的,因此不管是直接传入本身的Runnable、Callable实现类仍是构建FutureTask传入,本质上都是经过FutureTask去实现,没有什么区别;

以上就是对Future与FutureTask二者关系的一个大体的介绍与分析,其中若有不足与不正确的地方还望指出与海涵。

相关文章
相关标签/搜索