您的位置:首页 > 编程语言

高级并发编程学习-callable与Future的使用

2016-01-11 19:05 417 查看
应用场景:FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。另外,FutureTask还可以确保即使调用了多次run方法,它都只会执行一次Runnable或者Callable任务,或者通过cancel取消FutureTask的执行等。

注意:Callable接口不能替代Runnable,原因是Callable必须要和线程池Executors结合使用。Future取得的结果类型和callable返回的结果类型必须一致,通过泛型来实现。Callable要采用ExceutorService的submit方法提交,返回的future对象可以取消任务。FutureTask是接口Future的唯一的实现类。

使用步骤:

       
(1)  任务需要实现callable接口,注意这里的泛型:

@Override
public Integer call() throws Exception {
Integer result=0;
return result;
}


(2)生成任务并提交,存在两种方式。
         第一种:
 
Future<String> future=threadPool.submit(new Callable<String>(){
@Override
public String call() throws Exception {
Thread.sleep(2000);
return "hello";
}
});
使用例子:

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 CallableAndFuture {
public static void main(String[] args) {
ExecutorService threadPool=Executors.newSingleThreadExecutor();
//future的泛型类型必须要与callable的泛型类型相一致
Future<String> future=threadPool.submit(new Callable<String>(){

@Override
public String call() throws Exception {
Thread.sleep(2000);
return "hello";
}

});
System.out.println("等待结果....");
try {
//future.get方法会一直等待,也会阻塞线程
System.out.println("拿到结果:future.get方法的结果是"+future.get());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("aaaaaaaaaaaa");
threadPool.shutdown();//必须显示关闭
}

}


第二种:

FutureTask<Integer> ft = new FutureTask<Integer>(new ComputeTask(i, ""+i));
exec.submit(ft);


注意这里必须为FutureTask而非Future,因为ExecutorService.submit()方法声明为:
Future<?>submit(Runnabletask)或
Future<T> submit(Callable<T>task);

这就要求提交的任务需要实现了Runnable接口或Callable接口,因此这里需要使用FutureTask. 



示例代码:

import java.util.ArrayList;
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;
import java.util.concurrent.FutureTask;

public class FutureTaskForMultiCompute {

public static void main(String[] args) {

FutureTaskForMultiCompute inst=new FutureTaskForMultiCompute();
// 创建任务集合
List<Future<Integer>> taskList = new ArrayList<Future<Integer>>();
// 创建线程池
ExecutorService exec = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
//传入Callable对象创建FutureTask注意这里的ft实现了callable接口
FutureTask<Integer> ft = new FutureTask<Integer>(new ComputeTask(i, ""+i));
/*第二种提交方式为
Future<Integer>ft=exec.submit(new ComputeTask(i,""+i));*/
taskList.add(ft);
//提交给线程池执行任务,也可以通过exec.invokeAll(taskList)一次性提交所有任务;
exec.submit(ft);
}

System.out.println("所有计算任务提交完毕, 主线程接着干其他事情!");

// 开始统计各计算线程计算结果
Integer totalResult = 0;
for (Future<Integer> ft : taskList) {
try {
//FutureTask的get方法会自动阻塞,直到获取计算结果为止
totalResult = totalResult + ft.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}

// 关闭线程池
exec.shutdown();
System.out.println("多任务计算后的总结果是:" + totalResult);

}

}

import java.util.concurrent.Callable;

public class ComputeTask implements Callable<Integer> {

private Integer result = 0;
private String taskName = "";

public ComputeTask(Integer iniResult, String taskName){
result = iniResult;
this.taskName = taskName;
System.out.println("生成子线程计算任务: "+taskName);
}

public String getTaskName(){
return this.taskName;
}

@Override
public Integer call() throws Exception {
// TODO Auto-generated method stub

for (int i = 0; i < 100; i++) {
result =+ i;
}
// 休眠5秒钟,观察主线程行为,预期的结果是主线程会继续执行,到要取得FutureTask的结果是等待直至完成。
Thread.sleep(5000);
System.out.println("子线程计算任务: "+taskName+" 执行完成!");
return result;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: