Callable
Callable與Runnable類似,但是執行任務後能傳回結果;Future接口表示異步任務,它能拿到Callable的傳回值,即擷取結果。
Callable接口如下:
public interface Callable<V> {
V call() throws Exception;
}
這是一個泛型接口,傳回的類型就是傳遞進來的類型,或者抛出異常。
使用: 一般作為參數,詳見後面的例子
Future
Future能具體的Runnable或者Callable任務的執行進行取消、查詢是否完成、擷取結果。
接口如下:
public interface Future<V> {
// 取消對此任務的執行
boolean cancel(boolean mayInterruptIfRunning);
// 如果在任務正常完成前将其取消,則傳回 true
boolean isCancelled();
// 如果任務已完成傳回 true
boolean isDone();
// 擷取執行結果,該方法會阻塞一直等到任務執行完成
V get() throws InterruptedException, ExecutionException;
// 最多等待為使計算完成所給定的時間之後,擷取其結果,如果逾時,結果傳回null
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
Future的實作類:FutureTask
public class FutureTask<V> implements RunnableFuture<V> {
……
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
可以看到,FutureTask實作了Runnable和Future,既可以作為Runnable被線程執行,又可以作為Future得到Callable的傳回值。
FutureTask的兩個構造方法:
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
示例如下
使用場景:目前線程(線程A)需要依賴于另一個線程(線程B)的處理結果,而線程B處理結果需要一定的時間,Future模式就可以讓線程A的資料請求交給B,需要資料時再去get。而在B處理時A還能處理其他業務。
package com.learn;
import java.util.concurrent.Callable;
public class FooCallable implements Callable<String> {
private String name;
public FooCallable(String name) {
this.name = name;
}
@Override
public String call() throws Exception {
System.out.println("Task任務執行");
Thread.sleep();
return name;
}
}
package com.learn;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
public class FutureTaskTest {
public static void main(String[] args) {
FooCallable a = new FooCallable("A");
FutureTask<String> futureTask1 = new FutureTask<>(a);
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit(futureTask1);
System.out.println("主線程執行任務");
try {
if (!futureTask1.isDone()) { // 任務沒有完成,會等待,直到任務完成
System.out.println("FutureTask執行結果" + futureTask1.get());
}
} catch (Exception e) {
e.printStackTrace();
}
executorService.shutdown();
System.out.println("All執行完畢");
}
}
執行結果:
Task任務執行
主線程執行任務
FutureTask執行結果A
All執行完畢
示例2
采用submit(Callable)
package com.learn;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class FutureTaskTest {
public static void main(String[] args) {
FooCallable a = new FooCallable("A");
ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> ret = executorService.submit(a);
System.out.println("主線程執行任務");
try {
System.out.println("Task執行結果" + ret.get());
} catch (Exception e) {
e.printStackTrace();
}
executorService.shutdown();
System.out.println("All執行完畢");
}
}