1、Future的出现原因
我们在Java线程池ThreadPoolExecutor详解中利用execute(Runnable r)方法来异步执行任务,但是有一个缺点,就是无法执行带有返回值的任务。
所以引入了Future来解决这个问题。
2、Future详解
Future中有5个方法:
1、cancel():取消任务
2、isCancelled():任务是否取消成功
3、isDone():任务是否完成了
4、get():获取返回值,阻塞
5、get(long count,TimeUnit):按照count个unit超时时间来获取返回值,阻塞
ThreadPoolExecutor提供了三个方法,来获取返回值
1、submit(Runnable r)
因为Runnable的run方法是void的,没有返回值,所以Future.get()是null。
源码
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对象,result为null,具体的流程可以看最底下的源码。
2、submit(Runnable r,T result)
T result就是传入的对象。我们可以通过自定义Runnable来将result传入到自定义的Runnable中,在run()方法中对结果写入到result中。其中返回的对象future.get()==result。
例子如下:
public class TestThreadExecutor {
public static void main(String[] args) throws ExecutionException, InterruptedException {
BlockingQueue queue = new LinkedBlockingQueue(10);
ThreadPoolExecutor executor = new ThreadPoolExecutor(4,10,2,TimeUnit.SECONDS,queue);
//设置coreThread如果超时也会被取消
executor.allowCoreThreadTimeOut(true);
int[] arr = new int[2];
MyRunnable runnable = new MyRunnable(arr);
Future f = executor.submit(runnable,arr);
System.out.println(Arrays.toString((int[])f.get()));
}
}
class MyRunnable implements Runnable {
private int[] arr;
public MyRunnable(int[] arr){
this.arr = arr;
}
@Override
public void run() {
arr[0] = 111;
}
}
源码
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对象,result为传入的对象,具体的流程可以看最底下的源码。
3、submit(Callable c)
submit(Runnable r,T result)不太好用,需要每次都自定义Runnable和result,太麻烦了。
Callable更加好用,传入一个Callable对象就行。
Callable和Runnable是大致一样,只不过Callable能够返回值。
Callable callable = new Callable() {
@Override
public Object call() throws Exception {
String name = "777";
name += "6666";
return name;
}
};
Future f = executor.submit(callable);
System.out.println(f.get());
从上述代码可以看出,Callable中call()返回的对象就是future.get()得到的对象。
源码解析
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);//利用callable新建了一个FutureTask
execute(ftask);//会调用ftask.run()方法
return ftask;//返回一个FutureTask对象
}
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW;
}
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 {
//执行callable.call()
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
//将outcome设置为result
set(result);
}
} finally {
runner = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
//这里这里这里
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
future.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);
}
综上所述,还是submit(Callable c)比较好使!