Java Callable 和 Future 在多線程編程中被大量使用。在過去的幾篇文章中,我們學到了很多關於 Java 線程,但有時我們希望一個線程能夠返回我們可以使用的值。Java 5 引入了 java.util.concurrent.Callable 接口在並發包中,它類似於 Runnable 接口,但可以返回任何對象並且能夠拋出異常。
Java Callable
Java Callable 接口使用泛型來定義對象的返回類型。 Executors 類提供了有用的方法來在線程池中執行 Java Callable。由於 callable 任務是並行運行的,我們必須等待返回的對象。
Java Future
Java Callable 任務返回 java.util.concurrent.Future 物件。使用 Java Future 物件,我們可以查詢 Callable 任務的狀態並獲取返回的物件。它提供 get() 方法,該方法可以等待 Callable 完成,然後返回結果。Java Future 提供 cancel() 方法以取消相關聯的 Callable 任務。get() 方法還有一個重載版本,我們可以指定等待結果的時間,這對於避免當前線程長時間阻塞很有用。有 isDone() 和 isCancelled() 方法,以查詢相關聯 Callable 任務的當前狀態。以下是 Java Callable 任務的一個簡單示例,該示例在一秒後返回執行任務的線程名稱。我們使用 Executor 框架 並行執行 100 個任務,使用 Java Future 獲取提交任務的結果。
package com.journaldev.threads;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
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;
public class MyCallable implements Callable {
@Override
public String call() throws Exception {
Thread.sleep(1000);
//返回执行此可调用任务的线程名称
return Thread.currentThread().getName();
}
public static void main(String args[]){
//从Executors实用类获取ExecutorService,线程池大小为10
ExecutorService executor = Executors.newFixedThreadPool(10);
//创建一个列表以保存与Callable相关联的Future对象
List> list = new ArrayList>();
//创建MyCallable实例
Callable callable = new MyCallable();
for(int i=0; i< 100; i++){
//提交Callable任务以由线程池执行
Future future = executor.submit(callable);
//将Future添加到列表中,我们可以使用Future获取返回值
list.add(future);
}
for(Future fut : list){
try {
//打印Future的返回值,请注意控制台中的输出延迟
//因为Future.get()等待任务完成
System.out.println(new Date()+ "::"+fut.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
//现在关闭执行器服务
executor.shutdown();
}
}
执行以上程序后,您将注意到输出中的延迟,因为Java Future get()方法等待Java可调用任务完成。还要注意,只有10个线程在执行这些任务。以下是以上程序输出的片段。
Mon Dec 31 20:40:15 PST 2012::pool-1-thread-1
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-3
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-4
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-5
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-6
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-7
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-8
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-9
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-10
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
...
提示:如果我们想覆盖Java Future接口的一些方法,例如覆盖get()
方法以在一些默认时间后超时而不是无限期等待,在这种情况下,Java FutureTask类就派上用场,这是Future接口的基本实现。查看Java FutureTask Example以了解更多关于这个类的信息。
Source:
https://www.digitalocean.com/community/tutorials/java-callable-future-example