java核心-多线程-线程类(5)-Callable、Future和FutureTask
-
基本概念
<1>Callable,Callable和Runnable差不多,两者都是为那些其实例可能被另一个线程执行的类而设计的,最主要的差别在于Runnable不会
返回线程运算结果,Callable可以(假如线程需要返回运行结果)。
<2>Future,是一个接口表示异步计算的结果,它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。
<3>FutureTask是Future的实现类,也可以说是进阶类,优化了Future的一些缺点,比如Future.get会阻塞等等,它提供了对Future的基本实现。
可使用FutureTask包装Callable或Runnable对象,实现异步处理线程运行结果。FutureTask实现了Runnable和Future(看源码可以看出来),所以也可以
将FutureTask提交给Executor。一般使用FutureTask代替Future即可。 -
使用api
<1>Callable使用方法
call() //类似run()方法
<2>Future使用方法
cancel(boolean mayInterruptIfRunning) //取消任务,如果已经完成,返回false
isCancelled() //判断是否取消过
isDone() //判断是否完成,取消、完成、异常都会返回true
get() //获取执行结果,阻塞的
<3>FutureTask使用方法
cancel(boolean mayInterruptIfRunning)
isCancelled()
done() //重写它来实现异步处理线程执行结果
isDone()
run()
get()
- 使用示例
Callable+Futrue
private static class CallableThread implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("进入CallableThread的call()方法, 开始睡觉, 睡觉时间为" + System.currentTimeMillis());
Thread.sleep(10000);
System.out.println("睡觉结束");
return "123";
}
}
@Test
public void test2(){
ExecutorService executorService = Executors.newCachedThreadPool();
CallableThread callableThread = new CallableThread();
long l = System.currentTimeMillis();
System.out.println("任务提交前时间:" + l);
Future<String> submit = executorService.submit(callableThread);
try {
String s = submit.get();
}catch (Exception e){
}
System.out.println("获取结果的时间:" + (System.currentTimeMillis()-l));
}
执行结果
任务提交前时间:1556438172228
进入CallableThread的call()方法, 开始睡觉, 睡觉时间为1556438172229
睡觉结束
获取结果的时间:10006
这里的 Future.get 是阻塞方法 , 会一直等待Callable中线程任务执行完毕,是很低下的效率,
解决方式
1.可以使用FutureTask ,重写done方法
2.循环判断isDone,返回true的时候然后调用get()获取
Callable+FutureTask,异步处理线程运行结果
private static class CallableThread implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("进入CallableThread的call()方法, 开始睡觉, 睡觉时间为" + System.currentTimeMillis());
Thread.sleep(10000);
System.out.println("睡觉结束");
return "123";
}
}
private class MyFutureTask extends FutureTask<String>{
public MyFutureTask(Callable callable){
super(callable);
}
//FutureTask任务完成,会回调这个方法
@Override
protected void done() {
System.out.println("执行完调用了done()");
super.done();
try {
String s = this.get();
System.out.println("任务执行完毕:" + s);
System.out.println("当前时间:" + System.currentTimeMillis());
}catch (Exception e){
}
}
}
@Test
public void test3() {
ExecutorService executorService = Executors.newCachedThreadPool();
CallableThread callableThread = new CallableThread();
MyFutureTask myFutureTask = new MyFutureTask(callableThread);
executorService.submit(myFutureTask);
System.out.println("主线程执行结束");
try {
executorService.shutdown();
executorService.awaitTermination(12,TimeUnit.SECONDS);
} catch (Exception e) {
}finally {
executorService.shutdownNow();
}
}
执行结果
执行结果如下
主线程执行结束
进入CallableThread的call()方法, 开始睡觉, 睡觉时间为1556416923492
睡觉结束
执行完调用了done()
任务执行完毕:123
当前时间:1556416933493