本系列主要深入解析Java并发框架的内容,这是第七部分的内容,分析java并发中的Future
和Callable
类。
- Runnable与Callable接口
- Future类
- Callable和Future的关系
- 重要方法
- JDK中的Future
- 用FutureTask创建Future
- Future的注意点
Runnable与Callable接口
Runnable的缺陷
- 不支持返回一个返回值,run方法被void的修饰。
public abstract void run();
- 无法抛出check异常,也是因为原始接口的run方法是没有抛出异常的修饰的。只能用try,catch。
Callable 接口
类似与Runnable,被其他线程执行的任务。需要重写call
方法,并且是有返回值的。而且可以抛出异常。 V call() throws Exception;
Future类
- 作用:用子线程去执行,主线程不用去等待执行结束。只需要在合适的时刻去调用
get
方法获取结果就可以。Callable和Future的关系
- 可以用
Future.get()
来获取Callable接口返回的执行任务, Futuren.isDone()
来判断任务是否已经执行完成或者取消任务。- 如果
call()
方法还没执行完,调用get()
方法的线程会被阻塞,直到call()
方法返回结果,主线程才会恢复。 - 可以认为Future是一个存储器,存储了call()这个任务的结果。
重要方法
get()
:任务正常完成会返回,如果没有完成会被线程会被阻塞。如果call方法抛出异常,get方法抛出的异常都会是ExecutionException
,并且这异常是在get方法请求的时候才会被抛出。如果任务被取消,get方法抛出CancellationException
。任务超时的话抛出TimeOutException
。可以带超时的时间参数。cancel()
: 提前结束提交的任务。可以传入一个Boolean参数,决定要不要利用interrupt进行打断当前正在执行的任务。如果任务还没开始执行或者正在执行,会返回true;如果已经执行完毕了,返回false。isDone()
:只是执行完毕了,未必执行成功了。isCanceled()
:判断是否被取消了构造方法:
Future<?> f = service.submit(new Task());
,没有完成计算之前,f是空的。然后可以用f,get()
得到返回值。这里需要注意,task是需要继承Callable<>
类的,并且重写call()
方法。或者调用lambda方法。
方法一:继承Callable<>类
1 | import java.util.concurrent.*; |
方法二:lambda表达式
1 | import java.util.concurrent.*; |
JDK中的Future
Callable
是一个接口,内置了call()
方法,并且是可以抛出异常的。
Future
是一个接口,内置了cancel
,isCancelled()
,get()
,isDone()
,get(long, TimeUnit)
这几个方法。
RunnableFuture
是一个接口,利用接口的多继承,继承了Future
、Runnable
这两个接口,并且有一个run
方法用于完成真实的运算。
FuturnTask
是一个实现类,继承了RunnableFuture
接口。并且执行FT的run方法时,会调用Callable
接口中的call()
方法完成计算,并且存储,等到get()
方法调用时返回存储的结果。
用FutureTask创建Future
FutureTask是一种包装器,可以把Callable转化为Future和Runnable,实现了两者的接口。
第一步:建立一个Callable任务, Callable<V> callable = new Callable<>(){“重写call方法”};
第二步:生成一个FutureTask类,传入Callable类型,FutureTask<Integer> ft= new FutureTask<>(callable );
第三步:线程执行ft.run
,或者向线程池中提交executor.submit(ft)
。
第四步:得到返回值ft.get()
具体的实现可以参考高性能缓存。
Future的注意点
无法再次初始化,生命周期无法后退,只能在创建新的Future去完成新的任务。