FutureTask 异步回调介绍

本文介绍了Java中FutureTask类如何实现Callable接口的异步回调,详细讲解了Callable、FutureTask和Future接口的工作原理,并通过泡茶喝的案例展示了FutureTask的实际使用。

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

FutureTask 异步回调介绍

FutureTask 方式包含了一系列的 Java 相关的类,在 java.util.concurrent 包中。其中最为重要的是 FutureTask 类和 Callable 接口

Callable 接口介绍

在介绍 Callable 接口之前,先得重提一下旧的 Runnable 接口。Runnable 接口是在 Java 多线程中表示线程的业务代码的抽象接口。但是,Runnable 有一个重要的问题,它的 run 方法是没有返回值的。正因为如此,Runnable 不能用于需要有返回值的应用场景。为了解决 Runnable 接口的问题,Java 定义了一个新的和 Runnable 类似的接口—— Callable接口。并且将其中的代表业务处理的方法命名为 call,call 方法有返回值。

Callable的代码:

package java.util.concurrent;
@FunctionalInterface
public interface Callable<V> {
 //call 方法有返回值
 V call() throws Exception;
}

Callable 接口可以对应到 Runnable 接口;Callable 接口的 call 方法可以对应到 Runnable接口的 run 方法。相比较而言,Callable 接口的功能更强大一些。

Callable 接口与 Runnable 接口相比,还有一个很大的不同:Callable 接口的实例不能作为 Thread线程实例的 target 来使用;而 Runnable 接口实例可以作为 Thread 线程实例的 target 构造参数,开启一个 Thread 线程。
问题来了,Java 中的线程类型,只有一个 Thread 类,没有其他的类型。如果 Callable 实例需要异步执行,就要想办法赋值给 Thread 的 target 成员,一个 Runnable 类型的成员。为此,Java 提供了在 Callable 实例和 Thread 的 target 成员之间一个搭桥的类——FutureTask 类

FutureTask 类介绍

FutureTask 类代表一个未来执行的任务,表示新线程所执行的操作。

FutureTask 类的构造函数的源代码:

public FutureTask(Callable<V> callable) {
 if (callable == null)
 throw new NullPointerException();
 this.callable = callable;
 this.state = NEW; // ensure visibility of callable
}

FutureTask 类就像一座搭在 Callable 实例与 Thread 线程实例之间的桥。FutureTask 类的内部封装一个 Callable 实例,然后自身又作为 Thread 线程的 target。

总体来说,FutureTask 类首先是一个搭桥类的角色,FutureTask 类能当作 Thread 线程去执行目标 target,被异步执行;其次,如果要获取异步执行的结果,需要通过 FutureTask 类的方法去获取,在 FutureTask 类的内部,会将 Callable 的 call 方法的真正结果保存起来,以供外部获取。

在 Java 语言中,将 FutureTask 类的一系列操作,抽象出来作为一个重要的接口——Future 接口。当然,FutureTask 类也实现了此接口。

Future 接口介绍

Future 接口不复杂,主要是对并发任务的执行及获取其结果的一些操作。

主要提供了 3 大功能:
(1)判断并发任务是否执行完成。
(2)获取并发的任务完成后的结果。
(3)取消并发执行中的任务。

Future 接口的代码:

package java.util.concurrent;
public interface Future<V> {
//取消并发任务的执行。
 boolean cancel(booleanmayInterruptRunning);
 //获取并发任务的取消状态。
 booleanisCancelled();
 //获取并发任务的执行状态。
 booleanisDone();
 //获取并发任务执行的结果。(阻塞的)
 V get() throws InterruptedException,ExecutionException;
 //获取并发任务执行的结果。(超过设定的时间限制,就会抛出异常)
 V get(long timeout,TimeUnitunit) throws InterruptedException,
 ExecutionException,TimeoutException;
}
使用 FutureTask 类实现异步泡茶喝的实践案例

流程图:
 join 实现异步泡茶喝的流程

代码实现:

public class JavaFutureDemo {
    public static final int SLEEP_GAP = 500;

    public static String getCurThreadName() {
        return Thread.currentThread().getName();
    }

    static class HotWater implements Callable<Boolean> {
        @Override
        public Boolean call() throws Exception {
            try {
                System.out.println("洗好水壶");
                System.out.println("灌上凉水");
                System.out.println("放在火上");
                //睡一段时间 代表烧水
                Thread.sleep(SLEEP_GAP);
                System.out.println("水烧好了。");
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("烧水 线程发生异常中断");
                return false;
            }
            System.out.println("烧水 线程完成");
            return true;
        }
    }

    static class Wash implements Callable<Boolean> {

        @Override
        public Boolean call() throws Exception {
            try {
                System.out.println("洗茶杯");
                System.out.println("洗水壶");
                //睡一段时间 洗水壶
                Thread.sleep(SLEEP_GAP);
                System.out.println("洗完了。");
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("清洗 线程完成");
                return false;
            }
            System.out.println("清洗 线程结束");
            return true;
        }
    }


    public static void main(String[] args) {
        Callable<Boolean> hotWater = new HotWater();
        FutureTask<Boolean> hFuture = new FutureTask<>(hotWater);
        Thread hThread = new Thread(hFuture, "烧水线程~~~");

        Callable<Boolean> wash = new Wash();
        FutureTask<Boolean> wFuture = new FutureTask<>(wash);
        Thread wThread = new Thread(wFuture, "清洗线程~~~");

        hThread.start();
        wThread.start();
        Thread.currentThread().setName("主线程。");
        try {
            Boolean hBoolean = hFuture.get();
            Boolean wBoolean = wFuture.get();

            if (hBoolean && wBoolean) System.out.println("可以泡茶了,泡茶喝");
            else if (!hBoolean) System.out.println("水没烧好,烧水线程出现问题");
            else if (!wBoolean) System.out.println("还没有清洗好,清洗线程出现问题");
            else System.out.println("两个线程都有问题");

        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(getCurThreadName() + "运行结束!");
    }
}

首先,在上面的喝茶实例代码中使用了 Callable 接口,替代了 Runnable 接口,并且在 call 方法中返回了异步线程的执行结果。
其次,从 Callable 异步逻辑到异步线程,需要创建一个 FutureTask 类的实例,并通过 FutureTask类的实例,创建新的线程
最后,通过 FutureTask 类的实例,取得异步线程的执行结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值