在Java5之后,任务分两类:一类是实现了Runnable接口的类,一类是实现了Callable接口的类。两者都可以被 ExecutorService执行,但是Runnable任务没有返回值,而Callable任务有返回值。并且Callable的call()方法只能通过ExecutorService的(<T> task) 方法来执行,并且返回一个 <T><T>,是表示任务等待完成的 Future。
public interface Callable<V>返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。Callable 接口类似于,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。
类包含一些从其他普通形式转换成 Callable 类的实用方法。
Callable中的call()方法类似Runnable的run()方法,就是前者有返回值,后者没有。
当将一个Callable的对象传递给ExecutorService的submit方法,则该call方法自动在一个线程上执行,并且会返回执行结果Future对象。
同样,将Runnable的对象传递给ExecutorService的submit方法,则该run方法自动在一个线程上执行,并且会返回执行结果Future对象,但是在该Future对象上调用get方法,将返回null。
下面看个例子:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* Callable接口测试
*
* @author leizhimin 2008-11-26 9:20:13
*/
public class CallableDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<String>> resultList = new ArrayList<Future<String>>();
//创建10个任务并执行
for (int i = 0; i < 10; i++) {
//使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中
Future<String> future = executorService.submit(new TaskWithResult(i));
//将任务执行结果存储到List中
resultList.add(future);
}
//遍历任务的结果
for (Future<String> fs : resultList) {
try {
System.out.println(fs.get()); //打印各个线程(任务)执行的结果
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
//启动一次顺序关闭,执行以前提交的任务,但不接受新任务。如果已经关闭,则调用没有其他作用。
executorService.shutdown();
}
}
}
}
class TaskWithResult implements Callable<String> {
private int id;
public TaskWithResult(int id) {
this.id = id;
}
/**
* 任务的具体过程,一旦任务传给ExecutorService的submit方法,则该方法自动在一个线程上执行。
*
* @return
* @throws Exception
*/
public String call() throws Exception {
System.out.println("call()方法被自动调用,干活!!! " + Thread.currentThread().getName());
//一个模拟耗时的操作
for (int i = 999999; i > 0; i--) ;
return "call()方法被自动调用,任务的结果是:" + id + " " + Thread.currentThread().getName();
}
}
运行结果:
call()方法被自动调用,干活!!! pool-1-thread-1
call()方法被自动调用,干活!!! pool-1-thread-3
call()方法被自动调用,干活!!! pool-1-thread-4
call()方法被自动调用,干活!!! pool-1-thread-6
call()方法被自动调用,干活!!! pool-1-thread-2
call()方法被自动调用,干活!!! pool-1-thread-5
call()方法被自动调用,任务的结果是:0 pool-1-thread-1
call()方法被自动调用,任务的结果是:1 pool-1-thread-2
call()方法被自动调用,干活!!! pool-1-thread-2
call()方法被自动调用,干活!!! pool-1-thread-6
call()方法被自动调用,干活!!! pool-1-thread-4
call()方法被自动调用,任务的结果是:2 pool-1-thread-3
call()方法被自动调用,干活!!! pool-1-thread-3
call()方法被自动调用,任务的结果是:3 pool-1-thread-4
call()方法被自动调用,任务的结果是:4 pool-1-thread-5
call()方法被自动调用,任务的结果是:5 pool-1-thread-6
call()方法被自动调用,任务的结果是:6 pool-1-thread-2
call()方法被自动调用,任务的结果是:7 pool-1-thread-6
call()方法被自动调用,任务的结果是:8 pool-1-thread-4
call()方法被自动调用,任务的结果是:9 pool-1-thread-3
Process finished with exit code 0