JAVA Future类的使用详解
在并发编程中,Future接口提供了一种用于表示异步计算结果的机制,通过Future,我们可以启动异步任务,并在稍后获取其执行结果,本文将详细介绍Java中Future类的使用方法、应用场景及其与其他相关类的关系。
一、Future的应用场景
Future常用于以下场景:
异步任务:启动一个长时间运行的任务,并允许主线程继续执行其他操作,而不必等待任务完成。
并行处理:同时启动多个任务,并在所有任务完成后再进行下一步操作。
非阻塞模型:避免因等待某个耗时操作而阻塞整个程序的执行。
在准备早餐时,如果包子需要3分钟,凉菜只需1分钟,采用串行方式需要4分钟才能吃完早餐,但如果采用Future模式,可以同时准备包子和凉菜,从而缩短总时间。
二、Future的类图结构
Future接口定义了五个主要的方法:
V get() throws InterruptedException, ExecutionException
: 当任务结束后返回结果;如果任务未完成,则阻塞直到任务完成。
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
: 等待指定时间后返回结果;如果超时则抛出异常。
boolean cancel(boolean mayInterruptIfRunning)
: 取消任务;如果任务正在运行且mayInterruptIfRunning为true,则尝试中断任务。
boolean isDone()
: 判断任务是否已完成。
boolean isCancelled()
: 判断任务是否已取消。
实现类
RunnableFuture: 同时继承Future和Runnable接口,在成功执行run方法后,可以通过Future访问执行结果,典型实现类是FutureTask。
SchedualFuture: 表示一个延时的行为可以被取消,通常由定时任务ScheduledExecutorService生成。
CompleteFuture: 显示完成的Future,用作完成等级,触发依赖函数和行为。
ForkJoinTask: 基于任务的抽象类,通过ForkJoinPool执行轻量级任务。
三、Future的主要方法
1、get()方法: 获取任务的结果,如果任务尚未完成,则会阻塞当前线程直到任务完成。
Future<Integer> future = executor.submit(callableTask); Integer result = future.get(); // 如果任务未完成,则阻塞直到完成
2、get(long timeout, TimeUnit unit)方法: 在指定时间内等待任务完成,如果超时则抛出异常。
Integer result = future.get(5, TimeUnit.SECONDS); // 等待最多5秒
3、cancel(boolean mayInterruptIfRunning)方法: 取消任务。
boolean cancelled = future.cancel(true); // true表示如果任务正在运行则尝试中断它
4、isDone()方法: 检查任务是否已完成。
boolean done = future.isDone();
5、isCancelled()方法: 检查任务是否已被取消。
boolean cancelled = future.isCancelled();
四、Future示例demo
需求场景:等早餐过程中,包子需要3秒,凉菜需要1秒,普通的多线程需要四秒才能完成,先等凉菜,再等包子,采用Future模式可以优化这个过程。
普通多线程实现
public class BumThread extends Thread { @Override public void run() { try { Thread.sleep(3000); System.out.println("包子准备完毕"); } catch (InterruptedException e) { e.printStackTrace(); } } } public class ColdDishThread extends Thread { @Override public void run() { try { Thread.sleep(1000); System.out.println("凉菜准备完毕"); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) throws InterruptedException { long start = System.currentTimeMillis(); Thread t1 = new ColdDishThread(); t1.start(); t1.join(); Thread t2 = new BumThread(); t2.start(); t2.join(); long end = System.currentTimeMillis(); System.out.println("准备完毕时间:" + (end start)); }
Future模式实现
public static void main(String[] args) throws InterruptedException, ExecutionException { long start = System.currentTimeMillis(); Callable<String> ca1 = () > { Thread.sleep(1000); return "凉菜准备完毕"; }; FutureTask<String> ft1 = new FutureTask<>(ca1); new Thread(ft1).start(); System.out.println(ft1.get()); // 获取凉菜结果 Callable<String> ca2 = () > { Thread.sleep(3000); return "包子准备完毕"; }; FutureTask<String> ft2 = new FutureTask<>(ca2); new Thread(ft2).start(); System.out.println(ft2.get()); // 获取包子结果 long end = System.currentTimeMillis(); System.out.println("准备完毕时间:" + (end start)); }
在这个示例中,通过使用FutureTask,我们可以在等待凉菜的同时启动包子的准备过程,从而减少了总的等待时间。
五、相关问题与解答栏目
1、问题1:Future和Callable有什么区别?
回答:Future是一个接口,用于表示异步计算的结果;而Callable是一个泛型接口,类似于Runnable,但它可以返回一个结果并能抛出异常,Callable通常与Future一起使用,通过ExecutorService提交Callable任务后会返回一个Future对象,用于获取任务的结果。
2、问题2:如何取消一个已经提交的Future任务?
回答:可以使用Future接口中的cancel方法来取消任务,如果任务已经完成或已经被取消,则cancel方法返回false;否则根据mayInterruptIfRunning参数决定是否中断正在运行的任务,如果mayInterruptIfRunning为true且任务正在运行,则会尝试中断它。
到此,以上就是小编对于“JAVA Future类的使用详解”的问题就介绍到这了,希望介绍的几点解答对大家有用,有任何问题和不懂的,欢迎各位朋友在评论区讨论,给我留言。