本篇说明的是Callable和Future,它俩很有意思的,一个产生结果,一个拿到结果。
Callable接口类似于Runnable,从名字就可以看出来了,但是Runnable不会返回结果,并且无法抛出返回结果的异常,而Callable功能更强大一些,被线程执行后,可以返回值,这个返回值可以被Future拿到,也就是说,Future可以拿到异步执行任务的返回值,
public class Taskwithcallable implements Callable<String>{
private int id;
public Taskwithcallable(int id){
this.id=id;
}
@Override
public String call() throws Exception {
// TODO Auto-generated method stub
return "result of Taskwithcallable"+id;
}
public static void main(String[] args){
ExecutorService exec =Executors.newCachedThreadPool();
ArrayList<Future<String>> result=new ArrayList<Future<String>>();
//将线程池执行Taskwithcallable,返回值为调用的call方法,返回类型为Future,将结果放在ArrayList中
for(int i=0;i<=5;i++)result.add(exec.submit(new Taskwithcallable(i)));
for(Future<String> fs:result){
try {
System.out.println(fs.get());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
exec.shutdown();
}
}
}
}result of Taskwithcallable0
result of Taskwithcallable1
result of Taskwithcallable2
result of Taskwithcallable3
result of Taskwithcallable4
result of Taskwithcallable5
说说Runnable与Callable
Callable接口:
public interface Callable<V> {
V call() throws Exception;
}
Runnable接口:
public interface Runnable {
public abstract void run();
}
相同点:
- 两者都是接口;(废话)
- 两者都可用来编写多线程程序;
- 两者都需要调用Thread.start()启动线程;
不同点:
- 两者最大的不同点是:实现Callable接口的任务线程能返回执行结果;而实现Runnable接口的任务线程不能返回结果;
- Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛;
项目例子:
1:定义多线程类:实现Callable接口;
重写call方法:call方法的返回值是CircDoDetailDataOrgResult ,然后CircDoDetailDataOrgResult 的实现类中有RetCode,Errbuf两个属性,分别是作为执行多线程的call方法的返回结果和返回值!
public class CircCreateXmlCallable implements Callable<CircDoDetailDataOrgResult> {
private CircContext context;
private String filePath;
private CircRepOrgs repOrg;
private CircRepDataOrgs repDataOrg;
private CircIndexSets indexSet;
private CircPeriod period;
private ICircReportXmlAttachmentService xmlService;
private MessageSource messageSource;
public CircCreateXmlCallable(CircContext context, String filePath, CircRepOrgs repOrg, CircRepDataOrgs repDataOrg, CircIndexSets indexSet, CircPeriod period,
ICircReportXmlAttachmentService xmlService, MessageSource messageSource) {
this.context = context;
this.filePath = filePath;
this.repOrg = repOrg;
this.repDataOrg = repDataOrg;
this.indexSet = indexSet;
this.period = period;
this.xmlService = xmlService;
this.messageSource = messageSource;
}
@Override
public CircDoDetailDataOrgResult call() {
String retCode, errbuf;
CircDoDetailDataOrgResult result = new CircDoDetailDataOrgResult();
retCode = "0";
errbuf = " Completed Successfully.";
try {
this.xmlService.createXmlPerDistrictCodeByDOM(context, filePath, repOrg, repDataOrg, indexSet, period);
result.setRetCode(retCode);
result.setErrbuf(errbuf);
String msg = "District code:[" + repDataOrg.getDistrictCode() + "] xml file has been created sucessfully.";
CircLogUtil.info(msg);
} catch (Exception e) {
retCode = "2";
errbuf = "Completed With Error." + messageSource.getMessage(e.getMessage(), null, CircConstant.CIRC_DEFAULT_LOCALE) + ";" + MsgUtil.msg(e);
result.setRetCode(retCode);
result.setErrbuf(errbuf);
}
return result;
}
}
2:调用线程类,执行线程方法;
①首先使用ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(threadCount);创建线程池;
②接下来List<CircCreateXmlCallable> callables = new ArrayList<CircCreateXmlCallable>(); list中的CircCreateXmlCallable就是步骤1中定义的线程类,这个list用来装线程类;
:然后生成线程类的实例myCallable ;将myCallable加入到list中去,callables.add(myCallable);
:List<Future<CircDoDetailDataOrgResult>> futureList = executor.invokeAll(callables);线程池executor启动,执行
线程中的call方法,然后用Future接口将线程执行返回的结果接收到,future.get()得到结果!
@Service
@Transactional(rollbackFor = Exception.class)
public class CircReportXmlAttachmentServiceImpl extends BaseServiceImpl<CircReportXmlAttachment> implements ICircReportXmlAttachmentService {
@Autowired
private CircIndexSetsMapper indexSetsMapper;
@Autowired
private CircRepOrgsMapper repOrgsMapper;
@Autowired
private ICircContextService contextService;
@Autowired
private CircRepDataOrgsMapper repDataOrgsMapper;
@Autowired
private CircPeriodMapper periodMapper;
@Autowired
private ICircIndexResultsService indexResultsService;
@Autowired
private MessageSource messageSource;
public void threadCreateXml(CircContext context, String filePath, CircRepOrgs repOrg, List<CircRepDataOrgs> repDataOrgsList, CircIndexSets indexSet, CircPeriod period)
throws InterruptedException, ExecutionException, HdmpException, SQLException {
int threadCount = CircConstant.DEFAULT_CREATEXML_THREAD_COUNTS;
// 多线程循环处理
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(threadCount);
String msg = "Successfully fetched thread [" + threadCount + "].";
CircLogUtil.info(msg);
try {
List<CircCreateXmlCallable> callables = new ArrayList<CircCreateXmlCallable>();
for (CircRepDataOrgs repDataOrg : repDataOrgsList) {
CircCreateXmlCallable myCallable = new CircCreateXmlCallable(context, filePath, repOrg, repDataOrg, indexSet, period, this, messageSource);
callables.add(myCallable);
}
List<Future<CircDoDetailDataOrgResult>> futureList = executor.invokeAll(callables);
String districtCode, retCode, errbuf;
boolean existsErrorFlag = false;
for (Future<CircDoDetailDataOrgResult> future : futureList) {
retCode = future.get().getRetCode();
errbuf = future.get().getErrbuf();
if (!CircConstant.RETCODE_SUCESSFULL.equals(retCode)) {
existsErrorFlag = true;
districtCode = future.get().getDistrictCode();
msg = "District code:[" + districtCode + "].Fail to complete.The message is [" + errbuf + "]";
CircLogUtil.error(msg);
}
}
if (existsErrorFlag) {
throw new HdmpException("circ.threadcompletewitherror.exception");
}
} finally {
executor.shutdown();
}
}
例子2:
list<Future<map<String,Object>>> result接收返回的结果,结果为map<String,Object>类型的map集合;
返回结果: