Java Callable接口、Future接口及FutureTask类用法

Java Callable接口、Future接口及FutureTask类用法

Laughing
2025-04-24 / 0 评论 / 17 阅读 / 搜一下 / 正在检测是否收录...
温馨提示:
本文最后更新于2025年04月24日,已超过64天没有更新,若内容或图片失效,请留言反馈。

通常来讲,我们使用Runnable接口或者Thread类来创建一个新线程,但是他们有一个缺点,就是run方法没有返回值,如果我们需要开启线程后获得一个返回值,就可以使用Callable接口配合Future类来实现。

一、Callable接口

Callable⼀般是配合线程池⼯具ExecutorService来使⽤。ExecutorService可以使⽤submit⽅法来让⼀个Callable接⼝执⾏,它会返回⼀个Future,我们后续的程序可以通过这个Futureget⽅法得到结果。

可以看一下下面的Demo

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class FutureDemo implements Callable<String> {

    @Override
    public String call() throws Exception {
        return "Hello,World";
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        FutureDemo futureDemo = new FutureDemo();
        Future<String> tFuture = executorService.submit(futureDemo);
        try {
            System.out.println(tFuture.get());
        } catch (Exception exception) {
        }
    }

}

运行后,控制台会输出

Hello,World

二、Future接口

看一下Future接口的源代码

public interface Future<V> {

    /**
     * 试图取消一个线程的执行,但是不一定能成功,因为任务可能已完成或已取消或其他因素不能取消
     *
     * @param 是否允许打断正在执行的任务
     * @return 是否取消成功
     */
    boolean cancel(boolean mayInterruptIfRunning);

    /**
     * 获取线程是否已取消
     *
     * @return 线程完成前被取消返回true
     */
    boolean isCancelled();

    /**
     * 获取线程是否已完成
     *
     * 如果线程异常、被终止或者取消,都会返回true
     *
     * @return 线程完成返回true
     */
    boolean isDone();

    /**
     * 获取线程返回值
     *
     * @return 线程返回结果
     */
    V get() throws InterruptedException, ExecutionException;

    /**
     * 在给定时间内获取返回值,如果超时未获取到返回超时异常
     *
     * @param 获取结果最大等待时间
     * @param 时间计量单位
     * @return 结果
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

下面通过实际代码看一下Future接口的基本用法。

修改上面代码如下

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class FutureDemo implements Callable<String> {

    @Override
    public String call() throws Exception {
        return "Hello,World";
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        FutureDemo futureDemo = new FutureDemo();
        Future<String> tFuture = executorService.submit(futureDemo);
        // 判断线程是否完成
        System.out.println("线程是否完成:" + tFuture.isDone());
        // 判断线程是否取消
        System.out.println("线程是否取消:" + tFuture.isCancelled());
        try {
            System.out.println(tFuture.get());
            // 判断线程是否完成
            System.out.println("线程是否完成:" + tFuture.isDone());
            // 判断线程是否取消
            System.out.println("线程是否取消:" + tFuture.isCancelled());
        } catch (Exception exception) {
        }
    }
}

输出结果

线程是否完成:false
线程是否取消:false
Hello,World
线程是否完成:true
线程是否取消:false

可以看到,在获取到结果前,线程是未完成、未取消的,获取到结果后,线程正常结束,此时线程是已完成、未取消的。

下面代码继续修改,我们在获取结果之前先取消,因为线程可能来不及取消已经完成,所以我们加个让call方法睡眠1s

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.CancellationException;

public class FutureDemo implements Callable<String> {

    @Override
    public String call() throws Exception {
        Thread.sleep(1000);
        return "Hello,World";
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        FutureDemo futureDemo = new FutureDemo();
        Future<String> tFuture = executorService.submit(futureDemo);
        // 判断线程是否完成
        System.out.println("线程是否完成:" + tFuture.isDone());
        // 判断线程是否取消
        System.out.println("线程是否取消:" + tFuture.isCancelled());
        try {
            // 试图取消线程
            boolean isCancelled = tFuture.cancel(true);
            System.out.println("任务是否取消成功:" + isCancelled);
            // 判断线程是否完成
            System.out.println("线程是否完成:" + tFuture.isDone());
            // 判断线程是否取消
            System.out.println("线程是否取消:" + tFuture.isCancelled());
            // get的时候需要判断线程状态
            System.out.println(tFuture.get());
        } catch (CancellationException cancellationException) {
            System.out.println("线程已经被取消");
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

}

输出结果

线程是否完成:false
线程是否取消:false
任务是否取消成功:true
线程是否完成:true
线程是否取消:true
线程已经被取消

可以看到,线程已经取消成功,线程取消成功后,如果还是调用get方法,会抛出CancellationException异常,并且线程取消成功后,isDone方法也会返回true,代表线程已经完成。

最后一个方法,我们看一下增加get的重载方法。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.CancellationException;

public class FutureDemo implements Callable<String> {

    @Override
    public String call() throws Exception {
        Thread.sleep(1000);
        return "Hello,World";
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        FutureDemo futureDemo = new FutureDemo();
        Future<String> tFuture = executorService.submit(futureDemo);
        try {
            // get方法如果0.5秒内未获取到结果就抛出超时异常
            System.out.println(tFuture.get((long)0.5, TimeUnit.SECONDS));
        } catch (TimeoutException timeoutException) {
            System.out.println("超过0.5s未获取到结果");
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

}

输出结果

超过0.5s未获取到结果

三、FutureTask

FutureTask是Java自带的Future接口的实现类。FutureTask是实现的RunnableFuture接⼝,⽽RunnableFuture接⼝同时继承了Runnable接⼝和`Future接⼝。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.CancellationException;

public class FutureDemo implements Callable<String> {

    @Override
    public String call() throws Exception {
        return "Hello,World";
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        FutureDemo futureDemo = new FutureDemo();
        FutureTask<String> futureTask = new FutureTask<>(futureDemo);
        executorService.submit(futureTask);
        try {
            System.out.println(futureTask.get());
        }catch (Exception exception) {
            exception.printStackTrace();
        }
    }

}

输出结果:

Hello,World

文章摘抄自《深入浅出Java多线程.pdf》并对内容进行完善。

0

评论 (0)

取消