Java多线程中Callable、Future和FutureTask是什么意思

技术Java多线程中Callable、Future和FutureTask是什么意思小编给大家分享一下Java多线程中Callable、Future和FutureTask是什么意思,相信大部分人都还不怎么了解,因此分享这篇

边肖想和大家分享一下Java多线程中Callable、Future和FutureTask的含义。相信大部分人还是不太了解。因此,我想分享这篇文章供你参考。希望你看完这篇文章后收获多多。让我们一起来看看。

前言:

创建Threads有两种方法,一种是直接继承thread,另一种是实现Runnable接口。

这两种方法都有一个缺陷:在执行完任务后无法得到执行结果。

如果需要得到执行结果,必须共享变量或者使用线程通信来实现结果,使用起来比较麻烦。

从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行后获得任务执行结果。

1 Callable介绍

Callable接口代表一段可以调用并返回结果的代码;Future接口表示异步任务,是未完成任务给出的未来结果。因此,Callable用于产生结果,Future用于获得结果。

可调用接口使用泛型来定义其返回类型。Executors类提供了一些有用的方法来执行线程池中可调用的任务。由于Callable任务是并行的(并行意味着整体看起来是并行的,但是在某个时间点只有一个线程在执行),所以我们必须等待它返回的结果。java.util.concurrent.Future对象为我们解决了这个问题。线程池提交可调用任务后,返回一个Future对象,可以用来了解可调用任务的状态,得到可调用返回的执行结果。Future提供了一个get()方法,这样我们就可以等待Callable完成并获得它的执行结果。

2 Future介绍

2.1 在Future接口中声明方法

在Future接口中声明5种方法下面依次解释每个方法的作用:

Java多线程中Callable、Future和FutureTask是什么意思

00-1010 1)判断任务是否完成;

2)中断任务的能力;

3)得到任务执行的结果。

因为Future只是一个接口,不能直接用来创建对象,所以有下面的FutureTask。

2.2 Future提供了三种功能

我们先来看一下FutureTask的实现:

公共类FutureTaskV实现RunnableFutureV

FutureTask类实现了RunnableFuture接口,我们看一下RunnableFuture接口的实现:

public interface cerunnablefurtevextendrunnable,FutureV {

虚空运行();

}可以看出RunnableFuture继承了Runnable接口和Future接口,而FutureTask实现了RunnableFuture接口。因此,它可以作为Runnable由线程执行,也可以作为Future来获取Callable的返回值。

FutureTask提供了2个构造器:

public futuretask(CallableVcallable){ 0

}

public futuretask(runnable runnable,Vnbsp

;result) {
}

事实上,FutureTaskFuture接口的一个唯一实现类。

4 Future和FutureTask的使用

4.1 使用Callable+Future获取执行结果

public class CallableFutureTest {
    public static void main(String[] args) {
        //创建线程池
        ExecutorService es = Executors.newSingleThreadExecutor();
        //创建Callable对象任务
        CallableDemo calTask = new CallableDemo();
        //提交任务并获取执行结果
        Future<Integer> future = es.submit(calTask);
        //关闭线程池
        es.shutdown();
        try {
            Thread.sleep(2000);
            System.out.println("主线程在执行其他任务");
            if (future.get() != null) {
                //输出获取到的结果
                System.out.println("future.get()-->" + future.get());
            } else {
                //输出获取到的结果
                System.out.println("future.get()未获取到结果");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("主线程在执行完成");
    }
}
class CallableDemo implements Callable<Integer> {
    private int sum;
    @Override
    public Integer call() throws Exception {
        System.out.println("Callable子线程开始计算啦!");
        Thread.sleep(2000);
        for (int i = 0; i < 100; i++) {
            sum = sum + i;
        }
        System.out.println("Callable子线程计算结束!");
        return sum;
    }
}

Callable子线程开始计算啦!
Callable子线程计算结束!
主线程在执行其他任务
future.get()-->4950
主线程在执行完成

4.2 使用Callable+Future获取执行结果

public class CallableFutureTest {
    public static void main(String[] args) {
//      //创建线程池
//      ExecutorService es = Executors.newSingleThreadExecutor();
//      //创建Callable对象任务
//      CallableDemo calTask=new CallableDemo();
//      //提交任务并获取执行结果
//      Future<Integer> future =es.submit(calTask);
//      //关闭线程池
//      es.shutdown();
        //创建线程池
        ExecutorService es = Executors.newSingleThreadExecutor();
        //创建Callable对象任务
        CallableDemo calTask = new CallableDemo();
        //创建FutureTask
        FutureTask<Integer> futureTask = new FutureTask<>(calTask);
        //执行任务
        es.submit(futureTask);
        //关闭线程池
        es.shutdown();
        try {
            Thread.sleep(2000);
            System.out.println("主线程在执行其他任务");
            if (futureTask.get() != null) {
                //输出获取到的结果
                System.out.println("futureTask.get()-->" + futureTask.get());
            } else {
                //输出获取到的结果
                System.out.println("futureTask.get()未获取到结果");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("主线程在执行完成");
    }
}
class CallableDemo implements Callable<Integer> {
    private int sum;
    @Override
    public Integer call() throws Exception {
        System.out.println("Callable子线程开始计算啦!");
        Thread.sleep(2000);
        for (int i = 0; i < 100; i++) {
            sum = sum + i;
        }
        System.out.println("Callable子线程计算结束!");
        return sum;
    }
}

Callable子线程开始计算啦!
Callable子线程计算结束!
主线程在执行其他任务
futureTask.get()-->4950
主线程在执行完成

但其实这两种方法最终是一样的:
第一种方式Callable+Future最终也是以Callable+FutureTask的形式实现的。
在第一种方式中调用了: Future future = executor.submit(task);
那就让我们看看executor.submit(task)的源码吧:

//java.util.concurrent.AbstractExecutorService类中
   /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);//可以看到源码中其实是在submit(Callable<T> task)内部创建了一个RunnableFuture<T>接口实现类
        execute(ftask);
        return ftask;
    }

FutureTask又是RunnableFuture的实现类,那就再看看newTaskFor(Callable callable)里面干了什么:

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

以上是“Java多线程中Callable、Future和FutureTask是什么意思”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/60759.html

(0)

相关推荐

  • 衣补旁,衣补旁和四补旁有什么区别

    技术衣补旁,衣补旁和四补旁有什么区别一衣补旁、笔画数不同 1、四补旁:礻为示字旁,笔画数为四笔。 2、衣补旁:衤为衣字旁,笔画数为五笔。
    二、来源不同
    1、四补旁:同“示”。用作偏旁。俗称“示字旁”。
    2、衣补旁:

    生活 2021年10月24日
  • sparkmllib实战例子(sparkmllib学习方法)

    技术基于Spark Mllib文本分类的示例分析这篇文章将为大家详细讲解有关基于Spark Mllib文本分类的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。基于Spark M

    攻略 2021年12月16日
  • Ubuntu常用命令都有哪些

    技术Ubuntu常用命令都有哪些这篇文章给大家介绍Ubuntu常用命令都有哪些,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。我们使用 Ubuntu 系统,主要是使用 Ubuntu 系统下的命令,所以

    攻略 2021年11月11日
  • 两个不可数名词加and用is还是are,不可数名词是用is还是are

    技术两个不可数名词加and用is还是are,不可数名词是用is还是are不可数名词用is。 不可数名词属于单数两个不可数名词加and用is还是are,不过两个不可数名词用and连起来,就成复数要用are了。 不可数名词一

    生活 2021年10月26日
  • 苹果电脑如何切换输入法,Mac下如何切换输入法

    技术苹果电脑如何切换输入法,Mac下如何切换输入法1、如果你只有二个输入法苹果电脑如何切换输入法,一个英文输入法和一个中文输入法,(五笔或拼音),那我们可以用键盘快捷键来切换就行了,按下command键,再按一下空格键,

    生活 2021年10月28日
  • 如何分析java eclips

    技术如何分析java eclips如何分析java eclips,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。把下载到的eclipse-SDK-3.2.1-

    攻略 2021年12月2日