使用可呼叫類例項執行需要返回值的非同步任務
通常需要執行長時間執行的任務,並在完成任務後使用該任務的結果。
在這個例子中,我們將建立兩個類:一個實現 Callable <T>介面(其中 T 是我們希望返回的型別),另一個包含 main()
方法。
AsyncValueTypeTaskCompleter.java
import lombok.extern.java.Log;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
@Log
public class AsyncValueTypeTaskCompleter implements Callable<Integer> {
private int taskNumber;
public AsyncValueTypeTaskCompleter(int taskNumber) {
this.taskNumber = taskNumber;
}
@Override
public Integer call() throws Exception {
int timeout = ThreadLocalRandom.current().nextInt(1, 20);
try {
log.info(String.format("Task %d is sleeping", taskNumber));
TimeUnit.SECONDS.sleep(timeout);
log.info(String.format("Task %d is done sleeping", taskNumber));
} catch (InterruptedException e) {
log.warning(e.getMessage());
}
return timeout;
}
}
AsyncExample2.java
import lombok.extern.java.Log;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@Log
public class AsyncExample2 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<Integer>> futures = new ArrayList<>();
for (int i = 0; i < 10; i++){
Future<Integer> submittedFuture = executorService.submit(new AsyncValueTypeTaskCompleter(i));
futures.add(submittedFuture);
}
executorService.shutdown();
while(!futures.isEmpty()){
for(int j = 0; j < futures.size(); j++){
Future<Integer> f = futures.get(j);
if(f.isDone()){
try {
int timeout = f.get();
log.info(String.format("A task just completed after sleeping for %d seconds", timeout));
futures.remove(f);
} catch (InterruptedException | ExecutionException e) {
log.warning(e.getMessage());
}
}
}
}
}
}
執行 AsyncExample2.main()
導致以下輸出:
Dec 28, 2016 3:07:15 PM AsyncValueTypeTaskCompleter call
INFO: Task 7 is sleeping
Dec 28, 2016 3:07:15 PM AsyncValueTypeTaskCompleter call
INFO: Task 8 is sleeping
Dec 28, 2016 3:07:15 PM AsyncValueTypeTaskCompleter call
INFO: Task 2 is sleeping
Dec 28, 2016 3:07:15 PM AsyncValueTypeTaskCompleter call
INFO: Task 1 is sleeping
Dec 28, 2016 3:07:15 PM AsyncValueTypeTaskCompleter call
INFO: Task 4 is sleeping
Dec 28, 2016 3:07:15 PM AsyncValueTypeTaskCompleter call
INFO: Task 9 is sleeping
Dec 28, 2016 3:07:15 PM AsyncValueTypeTaskCompleter call
INFO: Task 0 is sleeping
Dec 28, 2016 3:07:15 PM AsyncValueTypeTaskCompleter call
INFO: Task 6 is sleeping
Dec 28, 2016 3:07:15 PM AsyncValueTypeTaskCompleter call
INFO: Task 5 is sleeping
Dec 28, 2016 3:07:15 PM AsyncValueTypeTaskCompleter call
INFO: Task 3 is sleeping
Dec 28, 2016 3:07:16 PM AsyncValueTypeTaskCompleter call
INFO: Task 8 is done sleeping
Dec 28, 2016 3:07:16 PM AsyncExample2 main
INFO: A task just completed after sleeping for 1 seconds
Dec 28, 2016 3:07:17 PM AsyncValueTypeTaskCompleter call
INFO: Task 2 is done sleeping
Dec 28, 2016 3:07:17 PM AsyncExample2 main
INFO: A task just completed after sleeping for 2 seconds
Dec 28, 2016 3:07:17 PM AsyncValueTypeTaskCompleter call
INFO: Task 9 is done sleeping
Dec 28, 2016 3:07:17 PM AsyncExample2 main
INFO: A task just completed after sleeping for 2 seconds
Dec 28, 2016 3:07:19 PM AsyncValueTypeTaskCompleter call
INFO: Task 3 is done sleeping
Dec 28, 2016 3:07:19 PM AsyncExample2 main
INFO: A task just completed after sleeping for 4 seconds
Dec 28, 2016 3:07:20 PM AsyncValueTypeTaskCompleter call
INFO: Task 0 is done sleeping
Dec 28, 2016 3:07:20 PM AsyncExample2 main
INFO: A task just completed after sleeping for 5 seconds
Dec 28, 2016 3:07:21 PM AsyncValueTypeTaskCompleter call
INFO: Task 5 is done sleeping
Dec 28, 2016 3:07:21 PM AsyncExample2 main
INFO: A task just completed after sleeping for 6 seconds
Dec 28, 2016 3:07:25 PM AsyncValueTypeTaskCompleter call
INFO: Task 1 is done sleeping
Dec 28, 2016 3:07:25 PM AsyncExample2 main
INFO: A task just completed after sleeping for 10 seconds
Dec 28, 2016 3:07:27 PM AsyncValueTypeTaskCompleter call
INFO: Task 6 is done sleeping
Dec 28, 2016 3:07:27 PM AsyncExample2 main
INFO: A task just completed after sleeping for 12 seconds
Dec 28, 2016 3:07:29 PM AsyncValueTypeTaskCompleter call
INFO: Task 7 is done sleeping
Dec 28, 2016 3:07:29 PM AsyncExample2 main
INFO: A task just completed after sleeping for 14 seconds
Dec 28, 2016 3:07:31 PM AsyncValueTypeTaskCompleter call
INFO: Task 4 is done sleeping
Dec 28, 2016 3:07:31 PM AsyncExample2 main
INFO: A task just completed after sleeping for 16 seconds
注意事項:
在上面的輸出中有幾點需要注意,
- 每次呼叫
ExecutorService.submit()
都會返回一個 Future 例項,它儲存在一個列表中供以後使用 - Future 包含一個名為
isDone()
的方法,可以在嘗試檢查其返回值之前檢查我們的任務是否已完成。在尚未完成的 Future 上呼叫Future.get()
方法將阻塞當前執行緒,直到任務完成,可能會否定從非同步執行任務中獲得的許多好處。 - 在檢查 Future 物件的返回值之前呼叫了
executorService.shutdown()
方法。這不是必需的,但是以這種方式完成以表明它是可能的。executorService.shutdown()
方法不會阻止已完成已提交給 ExecutorService 的任務,而是阻止將新任務新增到 Queue 中。