版权声明:本文为博主原创文章,未经博主允许不得转载。 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对象