一. Callable接口與Runnable接口區別
創建java線程,我們經常使用兩種方式:
- 一是直接繼承Thread
- 另一種是實現Runnable接口
但這兩種方式有一個缺陷:在執行完任務之後無法直接獲取執行結果。
1. 接口定義
1.1 Callable接口
public interface Callable<V> {
V call() throws Exception;
}
1.2 Runnable接口
public interface Runnable {
public abstract void run();
}
2. 區別
- Runnable沒有返回值;Callable可以返回執行結果(泛型)。
- Runnable異常只能在內部處理,不能往上繼續拋出;Callable接口的call()方法允許拋出異常。
- Callable需要配合FutureTask或Future使用。
二. Future接口和FutureTask實現類
1. Future接口定義了5個方法
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方法用來取消任務,如果取消任務成功則返回true,如果取消任務失敗則返回false。參數mayInterruptIfRunning表示是否允許取消正在執行卻沒有執行完畢的任務,如果設置true,則表示可以取消正在執行過程中的任務。如果任務已經完成,則無論mayInterruptIfRunning爲true還是false,此方法肯定返回false,即如果取消已經完成的任務會返回false;如果任務正在執行,若mayInterruptIfRunning設置爲true,則返回true,若mayInterruptIfRunning設置爲false,則返回false;如果任務還沒有執行,則無論mayInterruptIfRunning爲true還是false,肯定返回true。
- isCancelled方法表示任務是否被取消成功,如果在任務正常完成前被取消成功,則返回 true。
- isDone方法表示任務是否已經完成,若任務完成,則返回true;
- get()方法用來獲取執行結果,這個方法會產生阻塞,會一直等到任務執行完畢才返回;
- get(long timeout, TimeUnit unit)用來獲取執行結果,如果在指定時間內,還沒獲取到結果,就直接返回null。
2. FutureTask實現了RunnableFuture接口,RunnableFuture繼承了Runnable接口和Future接口
public class FutureTask<V> implements RunnableFuture<V>
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
三. 基本用法舉例
1. Runnable
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("線程執行中...");
}
};
Thread thread = new Thread(runnable);
thread.start();
2. Callable
2.1 FutureTask
Callable < Integer > callable = new Callable < Integer > () {
@Override
public Integer call() throws Exception {
System.out.println("線程執行中...");
return 100;
}
};
FutureTask < Integer > futureTask = new FutureTask < Integer > (callable);
new Thread(futureTask).start();
// 等待1秒,讓線程執行
TimeUnit.SECONDS.sleep(1);
if(futureTask.isDone()) {
System.out.println("獲取執行結果:" + futureTask.get());
}
2.2 Future
Callable < Integer > callable = new Callable < Integer > () {
@Override
public Integer call() throws Exception {
System.out.println("線程執行中...");
return 100;
}
};
ExecutorService service = Executors.newCachedThreadPool();
Future < Integer > future = service.submit(callable);
// 等待1秒,讓線程執行
TimeUnit.SECONDS.sleep(1);
if(futureTask.isDone()) {
System.out.println("獲取執行結果:" + future.get());
}