Java Callable 和 Future 在多线程编程中被广泛使用。在最近的几篇文章中,我们学到了很多关于 Java 线程,但有时我们希望线程能够返回我们可以使用的某个值。Java 5 引入了 java.util.concurrent.Callable 接口,它位于并发包中,类似于 Runnable 接口,但它可以返回任何对象并且能够抛出异常。
Java Callable
Java Callable 接口使用泛型来定义对象的返回类型。Executors 类提供了在线程池中执行 Java 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++){
//提交要由线程池执行的可调用任务
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 callable任务完成。还要注意,只有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示例以了解有关此类的更多信息。
Source:
https://www.digitalocean.com/community/tutorials/java-callable-future-example