获得执行器任务的结果
概述
创建线程的基本方法:实现Runnable接口没有方法能够返回线程执行结果。Executor Framework允许各并发任务返回结果。这个能力通过以下两个两个接口实现:
- Callable:这个接口声明了call方法,在这个方法里实现任务的具体逻辑,并可以返回任务的结果。
- Future:这个接口声明了一些方法来获取由Callabe对象产生的结果,并管理它们的状态。
示例
下面的示例演示了如何取得执行任务的结果:
public class CallableResultDemo {
public static void main(String[] args){
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
CallableReaultWorker worker = new CallableReaultWorker();
//保存各个工作线程对应的Future对象
List<Future<Long>> futures = new ArrayList<Future<Long>>(10);
//创建工作任务线程,并提交给执行器。
System.out.println("main:创建工作任务线程,并提交给执行器。");
for(int i=0; i<5; i++){
//注意:不能再使用execute方法,而是要使用submit方法,submit方法会返回这个任务对应的Future对象。
Future<Long> future = executor.submit(worker);
futures.add(future);
}
do{
//查看各个执行器状态
for(int i=0; i<futures.size(); i++){
System.out.println("main:任务线程" + i + "是否执行完成:" + futures.get(i).isDone());
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}while(executor.getActiveCount() > 0);
//输出各个执行器结果
for(int i=0; i<futures.size(); i++){
try {
System.out.println("main:任务线程" + i + "执行结果:" + futures.get(i).get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
executor.shutdown();
}
}
class CallableReaultWorker implements Callable<Long>{
@Override
public Long call() throws Exception {
long value = (long)(Math.random()*1000);
System.out.println(Thread.currentThread().getName() + ":执行结果:" + value);
Thread.sleep(value);
return value;
}
}
程序运行日志:
main:创建工作任务线程,并提交给执行器。
main:任务线程0是否执行完成:false
main:任务线程1是否执行完成:false
main:任务线程2是否执行完成:false
main:任务线程3是否执行完成:false
main:任务线程4是否执行完成:false
pool-1-thread-2:执行结果:614
pool-1-thread-1:执行结果:502
main:任务线程0是否执行完成:false
main:任务线程1是否执行完成:false
main:任务线程2是否执行完成:false
main:任务线程3是否执行完成:false
main:任务线程4是否执行完成:false
pool-1-thread-1:执行结果:444
main:任务线程0是否执行完成:true
main:任务线程1是否执行完成:false
main:任务线程2是否执行完成:false
main:任务线程3是否执行完成:false
main:任务线程4是否执行完成:false
pool-1-thread-2:执行结果:56
pool-1-thread-2:执行结果:821
main:任务线程0是否执行完成:true
main:任务线程1是否执行完成:true
main:任务线程2是否执行完成:false
main:任务线程3是否执行完成:true
main:任务线程4是否执行完成:false
main:任务线程0是否执行完成:true
main:任务线程1是否执行完成:true
main:任务线程2是否执行完成:true
main:任务线程3是否执行完成:true
main:任务线程4是否执行完成:false
main:任务线程0执行结果:502
main:任务线程1执行结果:614
main:任务线程2执行结果:444
main:任务线程3执行结果:56
main:任务线程4执行结果:821
关于获得全部结果
为了获得全部任务的执行结果必须等待全部任务执行完成,在上面的示例中是使用轮训等待的方式,如下:
ThreadPoolExecutor类提供了一种更简单的方法来等待执行器执行完所有任务,那就是调用ThreadPoolExecutor类的invokeAll方法。调用方法可以提交一个任务列表给执行器,并等待列表中所有任务执行完成。用调用invokeAll方法的方式改写上面示例如下:
do{
//查看各个执行器状态
for(int i=0; i<futures.size(); i++){
System.out.println("main:任务线程" + i + "是否执行完成:" + futures.get(i).isDone());
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}while(executor.getActiveCount() > 0);
ThreadPoolExecutor类提供了一种更简单的方法来等待执行器执行完所有任务,那就是调用ThreadPoolExecutor类的invokeAll方法。调用方法可以提交一个任务列表给执行器,并等待列表中所有任务执行完成。用调用invokeAll方法的方式改写上面示例如下:
public class InvokeAllDemo {
public static void main(String[] args){
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
List<CallableReaultWorker> tasks = new ArrayList<CallableReaultWorker>();
//保存各个工作线程对应的Future对象
List<Future<Long>> futures = new ArrayList<Future<Long>>(10);
//创建任务
for(int i=0; i<10; i++){
CallableReaultWorker worker = new CallableReaultWorker();
tasks.add(worker);
}
//提交给执行器。
System.out.println("main:提交给执行器,并等待任务执行完成。");
try {
futures = executor.invokeAll(tasks);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main:关闭执行器。");
executor.shutdown();
//输出各个执行器结果
System.out.println("main:任务执行完成,输出任务结果。");
for(int i=0; i<futures.size(); i++){
try {
System.out.println("main:任务线程" + i + "执行结果:" + futures.get(i).get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
程序执行日志:
main:提交给执行器,并等待任务执行完成。
pool-1-thread-2:执行结果:243
pool-1-thread-1:执行结果:295
pool-1-thread-2:执行结果:611
pool-1-thread-1:执行结果:364
pool-1-thread-1:执行结果:603
pool-1-thread-2:执行结果:268
pool-1-thread-2:执行结果:803
pool-1-thread-1:执行结果:974
pool-1-thread-2:执行结果:357
pool-1-thread-1:执行结果:449
main:关闭执行器。
main:任务执行完成,输出任务结果。
main:任务线程0执行结果:295
main:任务线程1执行结果:243
main:任务线程2执行结果:611
main:任务线程3执行结果:364
main:任务线程4执行结果:603
main:任务线程5执行结果:268
main:任务线程6执行结果:803
main:任务线程7执行结果:974
main:任务线程8执行结果:357
main:任务线程9执行结果:449