Java多线程之Callable接口的实现
1.接口的定义:
publicinterfaceCallable{ Vcall()throwsException; }
2.Callable和Runnable的异同
先看下Runnable接口的定义
publicinterfaceRunnable{ publicabstractvoidrun(); }
Callable的call()方法类似于Runnable接口中run()方法,都定义任务要完成的工作,实现这两个接口时要分别重写这两个方法,主要的不同之处是call()方法是有返回值的(其实还有一些区别,例如call方法可以抛出异常,run方法不可以),运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。
3.Callable类型的任务可以有两种执行方式:
我们先定义一个Callable任务MyCallableTask:
classMyCallableTaskimplementsCallable{ @Override publicIntegercall()throwsException{ System.out.println("线程在进行计算"); Thread.sleep(3000); intsum=0; for(inti=0;i<100;i++) sum+=i; returnsum; } }
①借助FutureTask执行
FutureTask类同时实现了两个接口,Future和Runnable接口,所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。
借助FutureTask执行的大体流程是:
Callablemycallabletask=newMyCallableTask(); FutureTask futuretask=newFutureTask (mycallabletask); newThread(futuretask).start();
通过futuretask可以得到MyCallableTask的call()的运行结果:futuretask.get();
②借助线程池来运行
线程池中执行Callable任务的原型例如:
publicinterfaceExecutorServiceextendsExecutor{ //提交一个Callable任务,返回值为一个Future类型Future submit(Callable task); //othermethods... }
借助线程池来运行Callable任务的一般流程为:
ExecutorServiceexec=Executors.newCachedThreadPool(); Futurefuture=exec.submit(newMyCallableTask());
通过future可以得到MyCallableTask的call()的运行结果:future.get();
在网上看到了几个比较好的代码例子:
a.Callable任务借助FutureTask运行:
publicclassCallableAndFutureTask{ publicstaticvoidmain(String[]args){ Callablecallable=newCallable (){ publicIntegercall()throwsException{ returnnewRandom().nextInt(100); } }; FutureTask future=newFutureTask (callable); newThread(future).start(); try{ Thread.sleep(5000); System.out.println(future.get()); }catch(InterruptedExceptione){ e.printStackTrace(); }catch(ExecutionExceptione){ e.printStackTrace(); } } }
b.Callable任务和线程池一起使用,然后返回值是Future:
publicclassCallableAndFuture{ publicstaticvoidmain(String[]args){ ExecutorServicethreadPool=Executors.newSingleThreadExecutor(); Futurefuture=threadPool.submit(newCallable (){ publicIntegercall()throwsException{ returnnewRandom().nextInt(100); } }); try{ Thread.sleep(5000);//可能做一些事情 System.out.println(future.get()); }catch(InterruptedExceptione){ e.printStackTrace(); }catch(ExecutionExceptione){ e.printStackTrace(); } } }
c.当执行多个Callable任务,有多个返回值时,我们可以创建一个Future的集合,例如:
classMyCallableTaskimplementsCallable{ privateintid; publicOneTask(intid){ this.id=id; } @Override publicStringcall()throwsException{ for(inti=0;i<5;i++){ System.out.println("Thread"+id); Thread.sleep(1000); } return"Resultofcallable:"+id; } } publicclassTest{ publicstaticvoidmain(String[]args){ //Callable mycallabletask=newMyCallableTask(1); ExecutorServiceexec=Executors.newCachedThreadPool(); ArrayList >results=newArrayList >(); for(inti=0;i<5;i++){ results.add(exec.submit(newMyCallableTask(i))); } for(Future fs:results){ if(fs.isDone()){ try{ System.out.println(fs.get()); }catch(Exceptione){ e.printStackTrace(); } }else{ System.out.println("MyCallableTask任务未完成!"); } } exec.shutdown(); } }
那么引入Callable接口具有哪些好处呢?
①可以获得任务执行返回值;
②通过与Future的结合,可以实现利用Future来跟踪异步计算的结果。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。