Java中Future与FutureTask使用与分析(2)

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对象,所以我们具体分析下上面代码中的三种情况:

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

2、你传入的已经是个自己构造的FutureTask对象,由于FutureTask其实是实现了Runnable接口的,它本身就是个Runaable实现类, sumbit方法还是会将它视为Runnable类来进行封装,并最终会执行FutureTask自己的run方法,一系列实现都在你传入的FutureTask对象内完成,所以你可以直接通过自己构建的FutureTask获取结果;

3、自己单独声明线程运行,跟第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的实现类并获取返回结果的过程。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/57df32242099a1f62a487e578518077b.html