Callable接口和Future接口

这篇具有很好参考价值的文章主要介绍了Callable接口和Future接口。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Callable接口和Future接口

创建线程的方式

1.继承Thread类2.实现Runnable接口3.Callable接口4.线程池方式

Callable接口

在继承Thread类和实现Runnable接口的方式创建线程时,线程执行的run方法中,返回值是void,即无法返回线程的执行结果,为了支持该功能,java提供了Callable接口。

Callable和Runnable接口的区别

  • 1.Callable中的call()方法,可以返回值,Runnable接口中的run方法,无返回值(void)。
  • 2.call()方法可以抛出异常,run()不能抛异常。
  • 3.实现Callable接口,必须重写call()方法,run是抽象方法,抽象类可以不实现。
  • 4.不能用Callable接口的对象,直接替换Runnable接口对象,创建线程。

Future接口

当call()方法完成时,结果必须存储在主线程已知的对象中,以便主线程可以知道线程返回的结果,可以使用Future对象。将Future视为保存结果的对象-该对象,不一定会将call接口返回值,保存到主线程中,但是会持有call返回值。Future基本上是主线程可以跟踪以及其他线程的结果的一种方式。要实现此接口,必须重写5个方法。

public interface Future<V> {//Future源码
    /**
     * Attempts to cancel execution of this task.  This attempt will
     * fail if the task has already completed, has already been cancelled,
     * or could not be cancelled for some other reason. If successful,
     * and this task has not started when {@code cancel} is called,
     * this task should never run.  If the task has already started,
     * then the {@code mayInterruptIfRunning} parameter determines
     * whether the thread executing this task should be interrupted in
     * an attempt to stop the task.
     *
     * <p>After this method returns, subsequent calls to {@link #isDone} will
     * always return {@code true}.  Subsequent calls to {@link #isCancelled}
     * will always return {@code true} if this method returned {@code true}.
     *
     * @param mayInterruptIfRunning {@code true} if the thread executing this
     * task should be interrupted; otherwise, in-progress tasks are allowed
     * to complete
     * @return {@code false} if the task could not be cancelled,
     * typically because it has already completed normally;
     * {@code true} otherwise
     */
    boolean cancel(boolean mayInterruptIfRunning);
    //用于停止任务,如果未启动,将停止任务,已启动,仅在mayInterrupt为true时才会中断任务

    /**
     * Returns {@code true} if this task was cancelled before it completed
     * normally.
     *
     * @return {@code true} if this task was cancelled before it completed
     */
    boolean isCancelled();

    /**
     * Returns {@code true} if this task completed.
     *
     * Completion may be due to normal termination, an exception, or
     * cancellation -- in all of these cases, this method will return
     * {@code true}.
     *
     * @return {@code true} if this task completed
     */
    boolean isDone();//判断任务是否完成,完成true,未完成false

    /**
     * Waits if necessary for the computation to complete, and then
     * retrieves its result.
     *
     * @return the computed result
     * @throws CancellationException if the computation was cancelled
     * @throws ExecutionException if the computation threw an
     * exception
     * @throws InterruptedException if the current thread was interrupted
     * while waiting
     */
    V get() throws InterruptedException, ExecutionException;//任务完成返回结果,未完成,等待完成

    /**
     * Waits if necessary for at most the given time for the computation
     * to complete, and then retrieves its result, if available.
     *
     * @param timeout the maximum time to wait
     * @param unit the time unit of the timeout argument
     * @return the computed result
     * @throws CancellationException if the computation was cancelled
     * @throws ExecutionException if the computation threw an
     * exception
     * @throws InterruptedException if the current thread was interrupted
     * while waiting
     * @throws TimeoutException if the wait timed out
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

Callable和Future是分别做各自的事情,Callable和Runnable类似,因为它封装了要在另一个线程上允许的任务,而Future用于存储从另一个线程获取的结果。实际上,Future和Runnable可以一起使用。创建线程需要Runnable,为了获取结果,需要Future。

FutureTask

Java库本身提供了具体的FutureTask类,该类实现了Runnable和Future接口,并方便的将两种功能组合在一起。并且其构造函数提供了Callable来创建FutureTask对象。然后将该FutureTask对象提供给Thread的构造函数以创建Thread对象。因此,间接的使用Callable创建线程。

关于FutureTask构造函数的理解
public class FutureTask<V> implements RunnableFuture<V> {//实现了RunnableFuture
	//该类的构造函数有两个
    public FutureTask(Callable<V> callable) {//
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
    //用此方法创建的线程,最后start()调用的其实是Executors.RunnableAdapter类的call(); 
    public FutureTask(Runnable runnable, V result) {//返回的结果,就是构造函数传入的值
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }
    //原因如下
    //使用FutureTask对象的方式,创建的Thread,在开启线程.start后,底层执行的是
   //Thread的方法 start()方法会调用start0(),但是调用这个start0()(操作系统创建线程)的时机,是操作系统决定的,但是这个start0()最后会调用run()方法,此线程的执行内容就在传入的对象的run()方法中
    public void run() {
        if (target != null) {
            target.run();
            //执行到这 target就是在创建Thread时,传递的Runnable接口的子类对象,FUtureTask方式就是传入的FutureTask对象
            //会执行FutureTask中的run()方法
        }
    }
    //FutureTask的run()
    public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;//类的属性
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    //会执行callable的call(),callable是创建TutureTask时,根据传入的Runnable的对象封装后的一个对象
                    //this.callable = Executors.callable(runnable, result);
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }
    //Executors类的callable
    public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
    }
    //最后执行到这里 Executors类的静态内部类RunnableAdapter
    static final class RunnableAdapter<T> implements Callable<T> {
        final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {
            task.run();
            return result;
        }
    }
}
public interface RunnableFuture<V> extends Runnable, Future<V> {//继承了Runnable, Future<V>接口
	void run();//
}
使用FutureTask类间接的用Callable接口创建线程
/**
 * @author 长名06
 * @version 1.0
 * 演示Callable创建线程 需要使用到Runnable的实现类FutureTask类
 */
public class CallableDemo {
    public static void main(String[] args) {
        FutureTask<Integer> futureTask = new FutureTask<>(() -> {
            System.out.println(Thread.currentThread().getName() +  "使用Callable接口创建的线程");
            return 100;
        });

        new Thread(futureTask,"线程1").start();
    }
}
核心原理

在主线程中需要执行耗时的操作时,但不想阻塞主线程,可以把这些作业交给Future对象来做。文章来源地址https://www.toymoban.com/news/detail-746620.html

  • 1.主线程需要,可以通过Future对象获取后台作业的计算结果或者执行状态。
  • 2.一般FutureTask多用于耗时的计算,主线程可以在完成自己的任务后,再获取结果。
  • 3.只有执行完后,才能获取结果,否则会阻塞get()方法。
  • 4.一旦执行完后,不能重新开始或取消计算。get()只会计算一次

小结

  • 1.在主线程需要执行比较耗时的操作时,但又不想阻塞主线程,可以把这些作业交给Future对象在后台完成,当主线程将来需要时,就可以通过Future对象获得后台作业的计算结果或者执行状态。
  • 2.一般FutureTask多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。
  • 3.get()方法只能获取结果,并且只能计算完后获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或抛出异常。且只计算一次,计算完成不能重新开始或取消计算。
    只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。

到了这里,关于Callable接口和Future接口的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java并发编程:Callable、Future和FutureTask

    在前面的文章中我们讲述了创建线程的 2 种方式,一种是直接继承 Thread ,另外一种就是实现 Runnable 接口。 这 2 种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果。 如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起

    2024年02月13日
    浏览(38)
  • JavaEE(系列14) -- 多线程(Callable)

    Callable 是一个 interface . 相当于把线程封装了一个 \\\"返回值\\\". 方便程序猿借助多线程的方式计算结果. 代码示例 : 创建线程计算 1 + 2 + 3 + ... + 1000, 不使用 Callable 版本 思路 : 创建一个类Result,包含 sum 表示最终结果, lock 表示线程同步使用的锁对象. main 方法中先创建 Result 实例,

    2024年02月06日
    浏览(36)
  • 多线程-Runable和Callable的区别

    在Java中,多线程可以通过实现Runnable接口或使用Callable接口来实现。这两种方式有一些区别,如下所示: 返回值: Runnable接口的run()方法没有返回值,它表示一个没有返回结果的任务。 Callable接口的call()方法有返回值,可以返回计算结果。 异常处理: Runnable接口的run()方法不

    2024年02月14日
    浏览(39)
  • 多线程之Runnable 、Callable 、Thread

    Java 提供了三种创建线程方法: 通过实现 Runnable 接口; 通过继承 Thread 类本身; 通过 Callable 和 Future 创建线程。 创建一个线程,最简单的方法是创建一个实现 Runnable 接口的类。 为了实现 Runnable,一个类只需要执行一个方法调用 run(),声明如下: 你可以重写该方法,重要的

    2024年02月07日
    浏览(52)
  • JUC-线程Callable使用与FutureTask源码阅读

    Callable简单使用 带返回值的线程(实现implements Callable返回值类型),使用示例 FutureTask面向对象方式学习 为了定义这样一个事物“有返回结果”,暂且称之为RunnableFuture。它集合了Runnable和Future两种事物 (其中Future接口 表示了一个任务的生命周期,是一个可取消的异步运算,可

    2024年02月04日
    浏览(35)
  • 【JavaEE初阶】 Callable 接口

    Callable 是一个 interface . 相当于把线程封装了一个 “返回值”. 方便程序猿借助多线程的方式计算结果 比如我们有以下需求 创建线程计算 1 + 2 + 3 + … + 1000, 如果我们不使用 Callable 不使用 Callable的实现过程如下: 建一个类 Result , 包含一个 sum 表示最终结果, lock 表示线程同步使

    2024年02月06日
    浏览(36)
  • 从源码角度深入解析Callable接口

    摘要: 从源码角度深入解析Callable接口,希望大家踏下心来,打开你的IDE,跟着文章看源码,相信你一定收获不小。 本文分享自华为云社区《一个Callable接口能有多少知识点?》,作者: 冰 河。 并发编程一直是程序员们比较头疼的,如何编写正确的并发程序相比其他程序来

    2023年04月18日
    浏览(47)
  • C++ 多线程编程(三) 获取线程的返回值——future

    C++11标准库增加了获取线程返回值的方法,头文件为future,主要包括 future 、 promise 、 packaged_task 、 async 四个类。 那么,了解一下各个类的构成以及功能。 future是一个模板类,它是传输线程返回值(也称为 共享状态 )的媒介,也可以理解为线程返回的结果就安置在future中。

    2024年02月02日
    浏览(45)
  • 多线程系列(十九) -Future使用详解

    在前几篇线程系列文章中,我们介绍了线程池的相关技术,任务执行类只需要实现 Runnable 接口,然后交给线程池,就可以轻松的实现异步执行多个任务的目标,提升程序的执行效率,比如如下异步执行任务下载。 而实际上 Runnable 接口并不能满足所有的需求,比如有些场景下

    2024年03月14日
    浏览(44)
  • C++11并发与多线程笔记(10) future其他成员函数、shared_future、atomic

    status = result.wait_for(std::chrono::seconds(几秒)); 卡住当前流程,等待std::async()的异步任务运 行一段时间,然后返回其状态std::future_status 。如果std::async()的参数是std::launch::deferred(延迟执行),则不会卡住主流程。 std::future_status是枚举类型,表示异步任务的执行状态。类型的取值

    2024年02月12日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包