原文地址 http://java.chinaitlab.com/advance/748786.html
自从Java平台的最开始,Runnable接口就已存在了。它允许你定义一个可由线程完成的任务。如大多数人所已知的那样,它只提供了一个run方法,该方法既不接受任何参数,也不返回任何值。如果你需要从一个未完成的任务中返回一个值,你就必须在该接口之外使用一个方法去等待该任务完成时通报的某种消息。例如,下面的示例就是你在这种情景下可能做的事情:
Runnable runnable = …;
Thread t = new Thread(runnable);
t.start();
t.join();
String value = someMethodtoGetSavedValue()
严格来说,上述代码并无错误,但现在可用不同的方法去做,这要感谢J2SE 5.0引入的Callable接口。不同于Runnable接口拥有run方法,Callable接口提供的是call方法,该方法可以返回一个 Object对象,或可返回任何一个在泛型化格式中定义了的特定类型的对象。
public interface Callable<V> {
V call() throws Exception;
}
因为你不可能把Callable对象传到Thread对象去执行,你可换用ExecutorService对象去执行Callable对象。该服务接受Callable对象,并经由submit方法去执行它。
<T> Future<T> submit(Callable<T> task)
如该方法的定义所示,提交一个Callable对象给ExecutorService会返回一个Future对象。然后,Future的get方法将会阻塞,直到任务完成。
为了证明这一点,下面的例子为命令行中的每个词都创建一个单独的Callable实例,然后把这些词的长度加起来。各个Callable对象将只是计算它自己的词的长度之和。Futures对象的Set集合将被保存以便从中获得计算用的值。如果需要保持返回值的顺序,则可换用一个List对象。
import java.util.*;
import java.util.concurrent.*;
public class CallableExample {
public static class WordLengthCallable
implements Callable {
private String word;
public WordLengthCallable(String word) {
this.word = word;
}
public Integer call() {
return Integer.valueOf(word.length());
}
}
public static void main(String args[]) throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(3);
Set<Future<Integer>> set = new HashSet<Future≶Integer>>();
for (String word: args) {
Callable<Integer> callable = new WordLengthCallable(word);
Future<Integer> future = pool.submit(callable);
set.add(future);
}
int sum = 0;
for (Future<Integer> future : set) {
sum += future.get();
}
system.out.printf("The sum of lengths is %s%n", sum);
system.exit(sum);
}
}
WordLengthCallable保存了每个词并使用该词的长度作为call方法的返回值。这个值可能会花点儿时间
去生成,不过在这个例子中,可以立即知道它。 call方法的唯一要求是这个值要在call方法的结尾处返回。
当Future的get方法稍后被调用时,如果任务运行得很快的话,Future将会自动得到这个值(如同本例的情
况),否则将一直等到该值生成完毕为止。多次调用get方法不会导致任务从该线程返回。因为该程序的目
的是计划所有字的长度之和,它不会强令Callable任务结束。如果最后一个任务在前三个任务之前完成,
也是没错的。对 Future的get方法的第一次调用将只会等待Set中第一个任务结束,而不会阻塞其它的任务
分别执行完毕。它只会等待当次线程或任务结束。这个特定的例子使用固定数线程池来产生ExecutorService
对象,但其它有效的方法也是可行的。