併發-9-Callable和Future
我們原來所說的繼承Thread或者實現Runnable的方式都無法獲得執行緒的執行結果,除非使用共享變數或者執行緒通訊,我們先看一下Runnable介面的原始碼:
public interface Runnable{ public abstract void run(){ } } 複製程式碼
run()的返回值為void,在任務執行完之後沒有返回
繼承Thread和實現Runnable這兩種方式,都無法獲得執行緒執行的結果
Callable可以彌補這一個缺點:
public interface Callable<V>{ V call() throws Exception } 複製程式碼
是一個泛型介面,返回值型別為傳入進來的的T型別的值
注意:Callable中方法是call而不是run
使用Callable
一般配合ExecutorService來使用:
其中聲明瞭若干個過載的submit方法
<T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result);//一般不使用 Future<?> submit(Runnable task); 複製程式碼
Future
Future就是對於具體的Runnable或者Callable任務的執行結果進行取消、查詢是否完成、獲取結果。必要時可以通過get方法獲取執行結果,該方法會阻塞直到任務返回結果
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; } 複製程式碼
cancel:取消任務
mayInterruptIfRunning:是否可以取消正在執行的任務
isCancelled:是否成功取消
isDone:是否已經完成
get:獲取執行結果,一直等到任務執行完畢才返回,阻塞等待
get(long timeout, TimeUint unit):用來獲取執行結果,指定時間內,還沒有獲取到結果,就返回null
也就是說Future用於非同步獲取執行結果或取消執行任務提供了三種功能:
1)判斷任務是否完成;
2)能夠中斷任務;
3)能夠獲取任務執行結果。
因為Future只是一個介面,所以是無法直接用來建立物件使用的,因此就有了下面的FutureTask。
FutureTask是Future的唯一實現
public interface RunnableFuture<V> extends Runnbale,Future<V> void run() } public class FutureTask implements RunnbaleFuture<V>{ public FutureTask(Callable<V> callable) public FutureTask(Runnable runnable,V result) } 複製程式碼
可以看出RunnableFuture繼承了Runnable介面和Future介面,而FutureTask實現了RunnableFuture介面。所以它既可以作為Runnable被執行緒執行,又可以作為Future得到Callable的返回值。
這段程式碼不給答案啦,動手實踐感受一下
public class FutureTaskUseDemo { public static void main(String[] agrs) throws InterruptedException, ExecutionException { ExecutorService executor = Executors.newCachedThreadPool(); /** * 使用FutureTask的Runnable特性 */ Thread thread = new Thread(new FutureTask<>(new BoilWater())); thread.start(); /** * 使用FutureTask的Callable特性------第一種寫法 */ FutureTask futureTask = new FutureTask(new BoilWater()); executor.submit(futureTask); out.println("做飯"); Thread.sleep(2000); out.println("飯做好了"); while (!futureTask.isDone()) { out.println("水還沒燒開呢"); Thread.sleep(1000); } out.println(futureTask.get()); /** * 使用FutureTask的Callable特性------第二種寫法 */ Future<String> submit = executor.submit(new BoilWater()); out.println("做飯"); Thread.sleep(2000); out.println("飯做好了"); while (!submit.isDone()) { out.println("水還沒燒開呢"); Thread.sleep(1000); } out.println(submit.get()); /** * 多個任務同時並行 */ CompletionService<Integer> cs = new ExecutorCompletionService<Integer>(executor); for (int i = 0; i < 5; i++) { final int taskId = i; cs.submit(() -> taskId); } for (int i = 0; i < 5; i++) { try { out.println(cs.take().get()); } catch (Exception e) { } } } } class BoilWater implements Callable<String> { @Override public String call() throws Exception { Thread.sleep(5000); return System.currentTimeMillis() + " 水燒開了"; } } 複製程式碼