併發-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() + " 水燒開了";
}
}
複製程式碼