查看Runnable接口的抽象方法發(fā)現(xiàn)它的返回值是void,所以不使用線程間通信他是無法獲取返回結果的双藕,Java提供了另一個具有返回結果的接口Callable昂羡,我們分析一下源代碼并寫幾個簡單的例子遂鹊。
Callable簡介
java.util.concurrent.Callable也是一個接口栋艳,它實現(xiàn)了一個方法call(),他的參數(shù)和返回值都是一個泛型V戳气,而且默認可以拋出異常链患。可以說是Runnable的進階版本瓶您,適合用于需要返回結果的復雜計算和處理過程麻捻。
java.util.concurrent.Callable源碼
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
Future,Runnable和FutureTask
java.util.concurrent.Future接口
Future是一個接口它定義了幾個基本的方法:
java.util.concurrent.Future源代碼(注釋太長刪掉了呀袱,需要可自行查看源代碼):
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;
java.util.concurrent.RunnableFuture接口
它繼承了Runnable和Future說明他的實現(xiàn)方法需要實現(xiàn)一個可執(zhí)行方法體run()和Future中的抽象方法贸毕。
java.util.concurrent.RunnableFuture源代碼:
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
java.util.concurrent.FutureTask類
FutureTask是RunnableFuture接口的實現(xiàn),首先分析他的兩個構造方法,都需要需要傳入一個,可選參數(shù)為返回值:
java.util.concurrent.FutureTask構造函數(shù)
/**
* Creates a {@code FutureTask} that will, upon running, execute the
* given {@code Callable}.
*
* @param callable the callable task
* @throws NullPointerException if the callable is null
*/
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
/**
* Creates a {@code FutureTask} that will, upon running, execute the
* given {@code Runnable}, and arrange that {@code get} will return the
* given result on successful completion.
*
* @param runnable the runnable task
* @param result the result to return on successful completion. If
* you don't need a particular result, consider using
* constructions of the form:
* {@code Future<?> f = new FutureTask<Void>(runnable, null)}
* @throws NullPointerException if the runnable is null
*/
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
isCancelled(),isDone(0和cannel()都是獲取線程的狀態(tài)和直接調用Thread.interrupt()中斷線程夜赵,這里不做描述明棍。看下核心的get()方法,如果未執(zhí)行完成則等待系統(tǒng)完成否則直接返回結果寇僧,另一個重載方法只是多了一個超時參數(shù)不在分析:
java.util.concurrent.FutureTask.get()方法
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
看下Run()方法摊腋,直接調用Callable.call()方法,并將執(zhí)行結果賦值給result屬性:
java.util.concurrent.FutureTask.run()方法
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可以說是一個加強版的Runnable嘁傀,他也是一個方法執(zhí)行體兴蒸,因為它實現(xiàn)了Runnable接口所以它可以作為Thread的初始化參數(shù),Thread執(zhí)行的時候會直接調用執(zhí)行他的run()方法细办;而且它實現(xiàn)了Future接口橙凳,在run()中調用call()并將結果存儲在屬性中供get()方法獲取,同時提供了一系列操作函數(shù)實現(xiàn)了線程執(zhí)行狀態(tài)的監(jiān)控和線程終端也就是任務取消功能笑撞。
FutureTask的幾種簡單使用方式
實現(xiàn)了Callable接口的MyThreadCallable類:
import java.util.concurrent.Callable;
public class MyThreadCallable implements Callable<String> {
private String name;
MyThreadCallable(String name){
this.name=name;
}
@Override
public String call(){
try {
Thread.sleep((int) Math.ceil(Math.random() * 100) * 100);
System.out.println("MyThreadCallable "+name+" 執(zhí)行了");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "MyThreadCallable "+name+" 返回值";
}
}
測試方法代碼
測試方法
public static void testThreadCallable(){
try { //需要捕獲Callable執(zhí)行的call()可能拋出的異常
/**
* 新建MyThreadCallable實現(xiàn)Callable接口
*/
FutureTask<String> futureTask=new FutureTask<>(new MyThreadCallable("A"));
new Thread(futureTask).start();
/**
* 匿名內部類方式實現(xiàn)FutureTask
*/
FutureTask<String> futureTask2=new FutureTask<String>(new Callable<String>(){
@Override
public String call() throws Exception {
Thread.sleep((int) Math.ceil(Math.random() * 100) * 100);
System.out.println("匿名內部類線程 B 執(zhí)行了");
return "匿名內部類線程 B 返回值";
}
});
new Thread(futureTask2).start();
/**
* 使用線程池
* 強烈建議使用線程池不要自己顯示創(chuàng)建線程
*/
FutureTask<String> futureTask3=new FutureTask<>(new MyThreadCallable("C"));
FutureTask<String> futureTask4=new FutureTask<>(new MyThreadCallable("D"));
ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(futureTask3);
executor.execute(futureTask4);
//最后獲取返回值岛啸,get()方法會阻塞當前進程
Thread.sleep(1000);
System.out.println(futureTask.get());
System.out.println(futureTask2.get());
System.out.println(futureTask3.get());
System.out.println(futureTask4.get());
}catch (Exception e){
e.printStackTrace();
}
}
執(zhí)行結果:
匿名內部類線程 B 執(zhí)行了
MyThreadCallable D 執(zhí)行了
MyThreadCallable C 執(zhí)行了
MyThreadCallable A 執(zhí)行了
MyThreadCallable A 返回值
匿名內部類線程 B 返回值
MyThreadCallable C 返回值
MyThreadCallable D 返回值