Java线程池详解:Future的使用和实现

java ExecutorService es = Executors.newFixedThreadPool(1);Future f = es.submit(new Callable() { @Override public Date call() throws Exception { Thread.sleep(5000); return new Date(); } });try { f.get(2000, TimeUnit.MILLISECONDS);} catch (TimeoutException e) { System.out....
Java线程池详解:Future的使用和实现
在处理异步任务时,Java线程池中的任务会返回一个Future对象,用于管理任务执行结果和状态。本文将详细介绍Future的使用和实现,包括获取执行结果、取消任务、获取任务状态以及FutureTask的详细实现。

1. 使用Future

1.1. 获取任务执行结果
Future提供了一个不带参数的get方法和一个带超时参数的get方法用于获取任务的执行结果。若任务执行完成,get方法会立即返回或抛出一个Exception;如果任务未完成,get方法会阻塞直到任务结束。带超时的get方法则会在指定时间内任务未完成时抛出TimeoutException。

java
ExecutorService es = Executors.newFixedThreadPool(1);
Future f = es.submit(new Callable() { @Override public Date call() throws Exception { Thread.sleep(5000); return new Date(); } });
try {
f.get(2000, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
System.out.println("timeout");
}
// 输出:timeout

如果任务抛出异常,get方法会将异常封装为ExecutionException并抛出,可以通过getCause方法获得原始异常。若任务被取消,get方法将抛出CancellationException。

1.2. 取消任务
通过Future可以取消任务,例如在get超时时抛弃任务时,应立即停止这些任务以避免为不再需要的结果浪费计算资源。

java
ExecutorService es = Executors.newFixedThreadPool(1);
Future f = es.submit(new Runnable() { @Override public void run() { throw new RuntimeException("task throw error test"); } });
// 等待任务执行完成
try {
f.get();
} catch (ExecutionException e) {
System.out.println(e.getCause().getMessage());
}
// 输出:task throw error test

1.3. 获取任务状态
Future提供了isDone和isCancelled两个方法来获取任务的状态。如果任务已完成,isDone返回true;如果任务被取消,isCancelled返回true。

java
/* 任务是否已完成。
完成可能是由于正常终止、异常或取消,在所有这些情况下,该方法将返回true。*/
boolean isDone();

/* Future是否已经被取消
在调用cancel后,无论cancel是否返回true改返回都将始终返回true。*/
boolean isCancelled();

2. FutureTask
FutureTask是Future的一个具体实现,实现了RunnableFuture接口。Executor框架下的线程池通常使用FutureTask作为底层实现。在AbstractExecutorService中,所有提交的任务都会被先封装为FutureTask,然后在execute方法中执行。FutureTask通过newTaskFor方法统一生成,并在任务执行前将其封装。

2.1. FutureTask的状态
FutureTask中的state字段记录了任务的当前状态,FutureTask中的操作在发起前都要先校验状态,操作后又要更新状态。FutureTask中的状态包括NEW、COMPLETING、NORMAL、EXCEPTIONAL、CANCELLED和INTERRUPTING,分别表示任务执行结束、执行抛出异常、被取消和被中断。

状态更新流程如下:通常调用get方法获取任务结果的线程与执行任务线程并非同一线程,因此为保证state字段的线程安全性,state字段的更新使用了Unsafe类的compareAndSwapObject方法,使用CAS算法进行更新。

2.2. get方法的实现
当调用FutureTask的get方法时,会阻塞直到任务执行完成或等待超时。其实现为在get方法中通过一个for(;;)循环一直循环到任务结束或超时,循环中执行:
- 当任务正常或异常执行完成后,会唤醒阻塞队列中的所有线程。
- 线程被唤醒后会返回任务的状态。
- 若调用get的线程被中断,则会立即抛出InterruptedException。
- 若任务被取消,则会抛出CancellationException。

2.3. FutureTask的执行
生成FutureTask时,需要指定异步任务,如指定的任务类型为Runnable类型的,则会被转换为Callable类型并将任务保存在callable字段中。通常,FutureTask的任务会在一个异步线程中执行,即在异步线程中执行其run方法。而FutureTask的run方法会调用其持有的异步任务的call方法,获取call的执行结果来更新FutureTask的结果和状态。

初始时任务的状态为NEW和执行任务的线程(runner字段保存了执行任务的线程)为null,因此若run开始时非NEW状态或runner非空,则任务已被执行或正在执行中。为避免重复发起执行,这里会直接返回。call正常执行结束后或抛出异常结束时都会使用返回的结果或异常去更新状态。

若执行正常完成,则将outcome字段设置为执行返回的结果,FutureTask状态最终更新为正常结束NORMAL。若执行时抛出异常结束,则将outcome设置为抛出的异常,FutureTask状态最终更新为非正常结束EXCEPTIONAL。

任务结果更新完成后会通知到阻塞等待结果的线程。任务执行结束后遍历等待队列中的所有节点,将节点的被阻塞等待的线程逐个唤醒,并移除节点。这些操作由finishCompletion实现。

2.4. cancel方法的实现
cancel方法可以取消任务。取消时,若选择了中断,则先更新状态为INTERRUPTING,然后对执行任务的线程发出中断,之后再将任务状态更新为INTERRUPTED。在中断和状态更新完成后,表示任务已经被取消,因此最后也需要调用finishCompletion唤醒所有等待该任务执行结束的线程。

以上内容详细介绍了Future和FutureTask的使用与实现,帮助开发者更好地理解和运用异步任务处理机制。通过这些机制,开发者可以更高效地管理任务执行,处理结果获取和取消需求。2024-08-21
mengvlog 阅读 10 次 更新于 2025-07-19 05:35:03 我来答关注问题0
檬味博客在线解答立即免费咨询

Java相关话题

Copyright © 2023 WWW.MENGVLOG.COM - 檬味博客
返回顶部