不会用Java Future,我怀疑你泡茶没我快, 又是超长图文!! (2)

从方法名称上相信你已经能看出这些方法的作用

// 取消任务 boolean cancel(boolean mayInterruptIfRunning); // 获取任务执行结果 V get() throws InterruptedException, ExecutionException; // 获取任务执行结果,带有超时时间限制 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; // 判断任务是否已经取消 boolean isCancelled(); // 判断任务是否已经结束 boolean isDone();

铺垫了这么多,看到这你也许有些乱了,咱们赶紧看一个例子,演示一下几个方法的作用

@Slf4j public class FutureAndCallableExample { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executorService = Executors.newSingleThreadExecutor(); // 使用 Callable ,可以获取返回值 Callable<String> callable = () -> { log.info("进入 Callable 的 call 方法"); // 模拟子线程任务,在此睡眠 2s, // 小细节:由于 call 方法会抛出 Exception,这里不用像使用 Runnable 的run 方法那样 try/catch 了 Thread.sleep(5000); return "Hello from Callable"; }; log.info("提交 Callable 到线程池"); Future<String> future = executorService.submit(callable); log.info("主线程继续执行"); log.info("主线程等待获取 Future 结果"); // Future.get() blocks until the result is available String result = future.get(); log.info("主线程获取到 Future 结果: {}", result); executorService.shutdown(); } }

程序运行结果如下:

不会用Java Future,我怀疑你泡茶没我快, 又是超长图文!!

如果你运行上述示例代码,主线程调用 future.get() 方法会阻塞自己,直到子任务完成。我们也可以使用 Future 方法提供的 isDone 方法,它可以用来检查 task 是否已经完成了,我们将上面程序做点小修改:

// 如果子线程没有结束,则睡眠 1s 重新检查 while(!future.isDone()) { System.out.println("Task is still not done..."); Thread.sleep(1000); }

来看运行结果:

不会用Java Future,我怀疑你泡茶没我快, 又是超长图文!!

如果子程序运行时间过长,或者其他原因,我们想 cancel 子程序的运行,则我们可以使用 Future 提供的 cancel 方法,继续对程序做一些修改

while(!future.isDone()) { System.out.println("子线程任务还没有结束..."); Thread.sleep(1000); double elapsedTimeInSec = (System.nanoTime() - startTime)/1000000000.0; // 如果程序运行时间大于 1s,则取消子线程的运行 if(elapsedTimeInSec > 1) { future.cancel(true); } }

来看运行结果:

不会用Java Future,我怀疑你泡茶没我快, 又是超长图文!!

为什么调用 cancel 方法程序会出现 CancellationException 呢? 是因为调用 get() 方法时,明确说明了:

调用 get() 方法时,如果计算结果被取消了,则抛出 CancellationException (具体原因,你会在下面的源码分析中看到)

不会用Java Future,我怀疑你泡茶没我快, 又是超长图文!!

有异常不处理是非常不专业的,所以我们需要进一步修改程序,以更友好的方式处理异常

// 通过 isCancelled 方法判断程序是否被取消,如果被取消,则打印日志,如果没被取消,则正常调用 get() 方法 if (!future.isCancelled()){ log.info("子线程任务已完成"); String result = future.get(); log.info("主线程获取到 Future 结果: {}", result); }else { log.warn("子线程任务被取消"); }

查看程序运行结果:

不会用Java Future,我怀疑你泡茶没我快, 又是超长图文!!

相信到这里你已经对 Future 的几个方法有了基本的使用印象,但 Future 是接口,其实使用 ExecutorService.submit() 方法返回的一直都是 Future 的实现类 FutureTask

不会用Java Future,我怀疑你泡茶没我快, 又是超长图文!!

接下来我们就进入这个核心实现类一探究竟

FutureTask

同样先来看类结构

不会用Java Future,我怀疑你泡茶没我快, 又是超长图文!!

public interface RunnableFuture<V> extends Runnable, Future<V> { void run(); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpgjwx.html