#|FutureTask 使用场景介绍

可以通过其提供的get方法,在FutureTask不同的状态下,以阻塞或者直接返回的方式或者结果。
FutureTask实现了Future和Runnable接口。以FutureTask是否调用了run方法,可以简单分为三种状态
1. 未启动。 run方法未执行。
2. 已启动。 run方法执行。
3. 已完成。 run方法正常执行完毕,或者调用cancel取消,或者run方法执行过程中抛出异常。

强调以上不同状态的特性,是为了突出一下这个场景的使用:多线程执行任务,任务只被执行一次。
FutureTask正常执行完成会返回值(不会再次执行),若中断,正在中断,或者取消时抛出异常。
看下代码,落地下:

Class TaskHandler{ // 记录执行过的任务 private final ConcurrentHashMap taskCache = new ConcurrentHashMap// hashet用Collections包装下也可以用,再根据put的返回,判断该任务已经存在。 public String execute(final String taskName) throws ExecutionException, InterruptException { while (true) { Future future = taskCache.get(taskName); if(future == null) { Callable task = new Callable() { @Override public String call() throws InterruptedException{ return taskName; } }; FutureTask futureTask = new FutureTask(task); future = taskCache.put(taskName, futureTask); if(future == null) { future = futureTask; futureTask.run(); } } try { future.get(); } catch(CancellationException e) { // 这个是get方法throw出来的异常 这里有两种异常CancellationException ExecutionException 只处理CancellationException,是因为这个异常是主动取消任务的,我们需要将其从taskCache中去除掉 taskCache.remove(taskName, future); } } } }

【#|FutureTask 使用场景介绍】以上代码有个小细节,这里指出一下。taskCache.remove(taskName, future),可不可以用taskCache.remove(taskName)?答案是可以的,前者是找到taskName对应的index后,调用future的equal判断是否是同一个对象,后者通过对taskName指针地址或者hashcode进行判断是否是同一个对象的。推荐使用第二种remove方法,因为String重写了equal和hashcode。

    推荐阅读