Callable,是Java1.5之後提供的一個接口,主要用於實現Java線程。通過Callable實現的線程可以獲取線程指定的返回值,並且在線程方法執行時可以對異常進行處理。正是由於這兩點使得Callable在使用場景上與Runnable不同。
Callable
Callable處於java.util.concurrent包下,該接口是一個泛型接口,泛型即指定的返回值的類型。在Callable接口下只定義了一個方法call(),該方法實現線程的具體方法並在方法完成返回結果(同時,有可能會拋出異常)。
package java.util.concurrent;
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和FutureTask
在上面說過通過Callable實現的線程可以具有返回值,但是我們應該要怎麼樣獲得線程的返回值呢?
這裏我們需要使用Future接口,Future接口代表一個異步操作的結果。在Future接口中定義了一系列的方法,用於獲取線程結果、判斷線程是否執行完成等。
public interface Future<V> {
/*
* 試圖取消此任務的執行。
*
* 如果任務已完成、或已取消,或者由於某些其他原因而無法取消,則該方法調用失敗,即返回值爲false。
* 當調用 cancel 時,如果調用成功,而此任務尚未啓動,則此任務將永不運行。如果任務已經啓動,
* 則 mayInterruptIfRunning 參數確定是否應該以試圖停止任務的方式來中斷執行此任務的線程。
*
* 此方法返回後,對 isDone() 的後續調用將始終返回 true。如果此方法返回 true,
* 則對 isCancelled() 的後續調用將始終返回 true。
*/
boolean cancel(boolean mayInterruptIfRunning);
/*
* 如果在任務正常完成前將其取消,則返回 true
*
*/
boolean isCancelled();
/*
* 如果任務已完成,則返回 true;否則,返回false
*
*/
boolean isDone();
/*
* 獲取任務的返回結果,該方法是一個阻塞方法,會一直等待線程結束纔可以獲取返回結果。
*
*/
V get() throws InterruptedException, ExecutionException;
/*
* 在指定的時間內,獲取任務的返回結果,否則會出現TimeoutException。
*
*/
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
FutureTask
FutureTask時Future的具體實現類,該類同時還實現了Runnable接口。
FutureTask一般常用於包裝Callable或者Runnable對象,由於FutureTask實現了Runnable接口,FutureTask可以通過Executor執行。
關於FutureTask在下面會演示其具體用法,這裏就不做詳細介紹了。
Callable實例演示
實現Callable完成線程的執行,有兩種方式:一是通過Thread;一是通過Executor。
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
/**
*
* @author zhangke
*/
public class Test {
/**
* @param args
* @throws ExecutionException
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException, ExecutionException {
execByExecutors();
execByThread();
}
public static void execByThread() {
try {
// 1、創建一個callable對象
Callable callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("正在後臺執行中...");
Thread.sleep(3000);
return (int) (Math.random() * 100);
}
};
// 2、通過FutureTask對callable對象進行封裝
FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);
// 3、啓動線程執行後臺任務
new Thread(futureTask).start();
// 4、判斷任務是否完成沒有完成則繼續阻塞主線程
while (!futureTask.isDone()) {
Thread.sleep(1000);
System.out.println("執行中...");
}
// 5、當線程任務完成,通過get方法獲取結果
System.out.println("執行完成,結果爲:" + futureTask.get());
} catch (Exception e) {
}
}
public static void execByExecutors() {
try {
// 1、獲取ExecutorService
ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
// 2、創建一個集合,用於存儲future
ArrayList<Future> futureList = new ArrayList<Future>();
//
for (int i = 0; i < 5; i++) {
// 3、 通過ExecutorService的submit提交執行Callable,將返回一個Future對象,通過集合保存線程結果
futureList.add(newSingleThreadExecutor.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("正在後臺執行中...");
Thread.sleep(3000);
return (int) (Math.random() * 100);
}
}));
}
// 4、遍歷線程的結果
for (Future future2 : futureList) {
System.out.println(future2.get());
}
System.out.println("執行完成");
// 5、關閉線程池
newSingleThreadExecutor.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
}
運行結果爲:
// execByThread
正在後臺執行中...
執行中...
執行中...
執行中...
執行完成,結果爲:80
// execByExecutor
正在後臺執行中...
16
正在後臺執行中...
正在後臺執行中...
75
52
正在後臺執行中...
正在後臺執行中...
81
40
執行完成