Future和Callable

本文详细介绍了Java并发编程中Callable与Future的基本概念及使用方法。对比了Callable与Runnable的区别,并解释了Future及其相关类如何实现异步计算结果的获取。此外还介绍了ExecutorCompletionService的用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Callable

Callable和Runnbale一样代表着任务,区别在于Callable有返回值并且可以抛出异常

Future

Future接口代表了线程池的异步计算结果。接口中的方法用来检查计算是否完成、等待完成和得到计算的结果。当计算完成后,只能通过get()方法得到结果,get方法会阻塞直到结果准备好了。如果想取消,那么调用cancel()方法。其他方法用于确定任务是正常完成还是取消了。一旦计算完成了,那么这个计算就不能被取消。

FutureTask类

FutureTask类实现了RunnableFuture接口,而RunnnableFuture接口继承了Runnable和Future接口,所以说FutureTask也是一个提供异步计算的结果的类。 FutureTask可以用来包装Callable或者Runnbale对象。因为FutureTask实现了Runnable接口,所以FutureTask也可以被提交给Executor。FutureTask既可以作为Runnable被执行,也可以作为Future得到Callable的返回值。

Future作为异步计算的顶层接口,Future对具体的Runnable或者Callable任务提供了三种操作:执行任务的取消、查询任务是否完成、获取任务的执行结果。其接口定义如下:

public interface Future<V> {

    /**
     * 试图取消对此任务的执行
     * 如果任务已完成、或已取消,或者由于某些其他原因而无法取消,则此尝试将失败。
     * 当调用 cancel 时,如果调用成功,而此任务尚未启动,则此任务将永不运行。
     * 如果任务已经启动,则 mayInterruptIfRunning 参数确定是否应该以试图停止任务的方式来中断执行此任务的线程
     */
    boolean cancel(boolean mayInterruptIfRunning);

    /**
     * 如果在任务正常完成前将其取消,则返回 true
     */
    boolean isCancelled();

    /**
     * 如果任务已完成,则返回 true
     */
    boolean isDone();

    /**
     *   如有必要,等待计算完成,然后获取其结果
     */
    V get() throws InterruptedException, ExecutionException;

    /**
     * 如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

RunnableFuture继承Future、Runnable两个接口,即所谓的Runnable的Future。提供了一个run()方法完成Future并允许访问其结果。

public interface RunnableFuture<V> extends Runnable, Future<V> {
    //在未被取消的情况下,将此 Future 设置为计算的结果
    void run();
}

AbstractExecutorService提供了newTaskFor()方法返回一个RunnableFuture,除此之外当我们把一个Runnable或者Callable提交给(调用submit())ThreadPoolExecutor或者ScheduledThreadPoolExecutor时,他们则会向我们返回一个FutureTask对象,如下:

    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }
        protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }

    <T> Future<T> submit(Callable<T> task)
    <T> Future<T> submit(Runnable task, T result)
    Future<> submit(Runnable task)

ExecutorCompletionService

实现了CompletionService,将执行完成的任务放到阻塞队列中,通过take或poll方法来获得执行结果

/**
 * Created by xmr on 2018/8/28.
 * 启动10条线程,谁先执行完成就返回谁
 */
public class CompletionServiceTest {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        //创建包含10条线程的线程池
        ExecutorService executor = Executors.newFixedThreadPool(10);
        CompletionService completionService = new ExecutorCompletionService(executor);
        for (int i =1; i <=10; i ++) {
            final  int result = i;
            completionService.submit(new Callable() {
                public Object call() throws Exception {
                    Thread.sleep(new Random().nextInt(5000));   //让当前线程随机休眠一段时间
                    return result;
                }
            });
        }
        System.out.println(completionService.take().get());   //获取执行结果
    }
}

 

参考:

http://cmsblogs.com/?p=2444

https://blog.csdn.net/qq_19431333/article/details/77483763

<think>我们正在讨论Java中的FutureCallable类。根据引用[1]-[5],我们可以总结如下: Callable接口: - 类似于Runnable,但可以返回结果或抛出异常。 - 定义了一个call()方法,该方法有返回值。 Future接口: - 表示异步计算的结果。 - 提供方法来检查计算是否完成,等待计算完成,并获取结果。 - 常用实现类为FutureTask。 使用步骤: 1. 创建Callable实现类(或使用Lambda表达式)并实现call()方法。 2. 将Callable任务提交给ExecutorService执行,返回一个Future对象。 3. 通过Future对象获取结果(get()方法会阻塞直到结果就绪)。 注意事项: - Future的get()方法是阻塞的,如果任务未完成,调用线程会一直等待。 - 可以使用带超时参数的get()方法避免无限期等待。 下面是一个示例,展示如何使用CallableFuture: ```java import java.util.concurrent.*; public class FutureCallableExample { public static void main(String[] args) { // 创建线程池 ExecutorService executor = Executors.newFixedThreadPool(2); // 创建Callable任务 Callable<Integer> task = () -> { Thread.sleep(1000); // 模拟耗时操作 return 123; }; // 提交任务并获取Future对象 Future<Integer> future = executor.submit(task); try { // 获取结果(阻塞直到结果就绪) Integer result = future.get(); System.out.println("任务结果: " + result); // 可以尝试使用带超时的get方法 // future.get(500, TimeUnit.MILLISECONDS); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } finally { executor.shutdown(); } } } ``` 在这个示例中: 1. 我们创建了一个线程池(ExecutorService)。 2. 定义了一个Callable任务,该任务休眠1秒后返回整数123。 3. 通过executor.submit()提交任务,返回一个Future对象。 4. 调用future.get()获取任务结果(会阻塞当前线程直到任务完成)。 5. 最后关闭线程池。 此外,我们还可以使用FutureTask类,它同时实现了RunnableFuture接口,因此可以直接交给Thread执行: ```java // 使用FutureTask FutureTask<Integer> futureTask = new FutureTask<>(task); new Thread(futureTask).start(); // 启动线程 try { Integer result = futureTask.get(); // 获取结果 System.out.println("FutureTask结果: " + result); } catch (Exception e) { e.printStackTrace(); } ``` 引用[4]中提到,Future的get()方法是阻塞的,如果多个任务提交,获取结果时可能会因为前面任务耗时较长而阻塞。因此,在实际应用中,我们可以考虑使用CompletableFutureJava 8引入)来避免这个问题,它提供了更强大的异步编程能力。 §§相关问题§§ 1. 如何避免Future.get()的阻塞问题? 2. CallableRunnable的主要区别是什么? 3. 如何取消一个正在执行的Future任务? 4. CompletableFuture相比Future有哪些优势? [^1]: 常用Java代码-Java中的FutureCallable接口。 [^2]: JAVA FutureCallable的实践教程。 [^3]: java callable用法_Java使用CallableFuture创建线程操作示例。 [^4]: Java并发类API -- FutureCallable。 [^5]: [Java多线程] FutureCallable的使用解析。</think>### JavaFuture Callable 类的使用详解 #### 一、核心概念 1. **Callable 接口** - 替代 `Runnable` 的可返回结果的任务接口 - 定义 `V call() throws Exception` 方法 - 特点:可返回结果、可抛出受检异常[^2][^3] 2. **Future 接口** - 表示异步计算的结果 - 提供方法:检查计算状态、获取结果、取消任务 - 实现类:`FutureTask`[^4] #### 二、使用步骤与示例 ```java import java.util.concurrent.*; public class FutureCallableDemo { public static void main(String[] args) throws Exception { // 1. 创建线程池 ExecutorService executor = Executors.newFixedThreadPool(2); // 2. 创建Callable任务(Lambda表达式) Callable<Integer> task = () -> { Thread.sleep(1000); // 模拟耗时操作 return ThreadLocalRandom.current().nextInt(1, 100); }; // 3. 提交任务获取Future对象 Future<Integer> future = executor.submit(task); System.out.println("主线程继续执行其他任务..."); // 4. 获取结果(阻塞直到完成) Integer result = future.get(); System.out.println("异步结果: " + result); // 5. 关闭线程池 executor.shutdown(); } } ``` #### 三、核心方法解析 1. **Future 关键方法**: ```java future.isDone(); // 检查任务是否完成 future.get(2, TimeUnit.SECONDS); // 带超时的结果获取 future.cancel(true); // 取消任务(true表示中断线程) ``` 2. **Callable 实现**: ```java // 自定义Callable实现 class DataProcessor implements Callable<String> { @Override public String call() throws Exception { // 数据处理逻辑 return "处理完成"; } } ``` #### 四、高级用法:FutureTask ```java // 直接使用FutureTask FutureTask<String> futureTask = new FutureTask<>(() -> { return "FutureTask结果"; }); new Thread(futureTask).start(); // 启动线程 System.out.println(futureTask.get()); // 获取结果 ``` #### 五、最佳实践与注意事项 1. **避免阻塞**: - 使用 `future.isDone()` 检查状态后再调用 `get()` - 设置超时参数防止永久阻塞[^4] ```java if (future.isDone()) { result = future.get(); } ``` 2. **异常处理**: ```java try { future.get(); } catch (ExecutionException e) { Throwable cause = e.getCause(); // 获取实际异常 } ``` 3. **资源释放**: - 始终在 `finally` 块中关闭线程池 ```java finally { executor.shutdown(); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值