java线程池执行有返回值线程源码详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq32933432/article/details/80171829

java线程池提供了几种执行线程的方式,这里主要讨论关于执行有返回值的线程的实现原理

方式一:

使用方式:

ExecutorService executorService = Executors.newSingleThreadExecutor();
Future future = executorService.submit(new impleCallable());
String sss = (String) future.get();
System.out.println(sss);
public class impleCallable implements  Callable{
        @Override
        public Object call() throws Exception {
            return "我是实现了Callable的一个线程";
        }
    }

输出:

我是实现了Callable的一个线程

源码:

下面看调用的submit方法

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(Callable<T> callable) {
        return new FutureTask<T>(callable);
 }

可以看到是把我们实现了Callabe的对象封装成了一个FutureTask对象,并且调用了线程池的execute()方法,咦。。这个方法不是我们平常把线程丢到线程池里执行的方法吗?为啥我们调用的是线程池的submit()方法最终是调用了execute()方法呢?这个FutureTask何许人也?下面来看。

public class FutureTask<V> implements RunnableFuture<V> {
    public void run() {
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                try {
                    result = c.call();
                } catch (Throwable ex) {
                }
                if (ran)
                    set(result);
            }
        }
    }
}
protected void set(V v) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = v;
        }
    }

可以看到这个FutureTask本身也是实现Runnable接口,也就是他也是一个线程,看他的run方法可以看到他最终调用的是我们submit(T)的时候传过来的对象的call方法,并且把返回值赋值给result.然后调用set方法把result复制给outcome。至此,线程执行完毕,并且返回值也赋值给了outcome.那么如何获取这个outcome呢,下面我们看FutureTask的get()方法

public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);//等待线程执行完毕
        return report(s);
    }
private V report(int s) throws ExecutionException {
        Object x = outcome;
        if (s == NORMAL)
            return (V)x;
        if (s >= CANCELLED)
            throw new CancellationException();
        throw new ExecutionException((Throwable)x);
    }

可以看到,get方法就是把outcome给返回出去了。

方式二

使用方式

 ExecutorService executorService = Executors.newSingleThreadExecutor();
        Future future = executorService.submit(new impleRunable(),"我是一个实现了Runnable的线程");
        String sss = (String) future.get();
        System.out.println(sss);

输出

我是一个实现了Runnable的线程

源码

下面看调用的submit方法

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;
    }
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }
public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }
public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, 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;
        }
    }

可以看到与方式一不同的地方在于参数的不同,但是可以看到,最终都是把Runnable对象封装成Callable对象的实现类RunnableAdapter,然后在call()中把我们传进去的参数result ruturn出来。

总结:

两种方式的背后实现其实是同一套,都是基于Callable,第二种方式会把传进去的Runnable封装成Callable方法,并且call中返回的是我们传进去的result对象

猜你喜欢

转载自blog.csdn.net/qq32933432/article/details/80171829
今日推荐