Callable、Runnable,Future和FutureTask之间关系

创建线程的两种方式:继承Thread类 或 实现Runnable接口,重写run方法。

Thread类本身也实现了Runnable接口,Runnable接口源码:

run方法是无返回值的,所以在JDK1.5出现了Callable接口


 关系类图


Callable

Callable接口源码

Callable是一个函数式接口(接口中仅有一个方法),也是一个泛型接口,返回值类型和泛型一致


Future

Future接口源码

cancel:取消任务的执行,如果任务已完成或已被取消,则返回false

isCancelled:判断任务是否被取消

isDone:判断任务是否完成

get():阻塞获取任务的执行结果

get(long timeout, TimeUnit unit):在规定的时间内,阻塞获取任务的执行结果

Future接口提供了取消任务,任务状态查询,任务结果获取的能力;

Future机制就是为了解决多线程返回值的问题;


RunnableFuture

RunnableFuture接口源码

RunnableFuture继承了Runnable和Future两个接口,也就同时具备其两个接口的功能


FutureTask

FutureTask是真正工作的处理类,实现了RunnableFuture接口,而RunnableFuture接口继承了Runnable和Future接口,所以FutureTask既可以作为Runnable被Thread执行,也可以获取Future异步执行的结果;

FutureTask两个构造方法,一个接收Callable的参数实例,另一个接收Runnable的参数实例

 

 

 当传入的参数是Runnable时,通过Executors.callable(runnable, result)方法将其转成Callable类型(最终都是执行Callable类型的任务),返回值类型为V(指定的泛型类型)

RunnableAdapter适配器


 FutureTask-demo示例

ExecutorService线程池接口中,sumbit方法即定义了Runnable入参类型,也定义了Callable入参类型

package com.example.demo.test;

import java.util.concurrent.*;

public class RunnableFutureTest {

    private static ExecutorService pool = Executors.newFixedThreadPool(2);

    public static void main(String[] args) throws Exception {
        testFuture(20);
        testRunnable(20);
    }

    /**
     * new Thread().start()新建一个线程,启动线程(实际执行run方法,无返回值)
     */
    static void testRunnable(int number) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("runnable sum:" + calcOneToTargetSum(number));
            }
        }).start();
    }

    /**
     * Runnable:实现run(),无返回值,不可以抛出异常
     * Callable:实现call(),有返回值,可以抛出异常
     * Runnable可以直接交给Thread来执行
     * Callable不可以直接交给Thread来执行,一般交给ExecutorService执行
     */
    static void testFuture(int number) {
        try {
            Future<?> result1 = pool.submit(new Runnable() {
                @Override
                public void run() {
                    calcOneToTargetSum(number);
                }
            });
            // 无返回值,get()会阻塞
            System.out.println("result1:" + result1.get());

            Future<Integer> result2 = pool.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    return calcOneToTargetSum(number);
                }
            });
            // 有返回值,get()会阻塞
            System.out.println("result2:" + result2.get());

            FutureTask<Integer> futureTask1 = new FutureTask<>(new Runnable() {
                @Override
                public void run() {
                    calcOneToTargetSum(number);
                }
            }, calcOneToTargetSum(number));
            pool.submit(futureTask1);
            // 有返回值,get()会阻塞
            System.out.println("result3:" + futureTask1.get());

            FutureTask<Integer> futureTask2 = new FutureTask<>(new Runnable() {
                @Override
                public void run() {
                    calcOneToTargetSum(number);
                }
            }, calcOneToTargetSum(number));
            pool.submit(futureTask2);
            // Executors.callable会将Runnable转换为Callable,固有返回值,get()会阻塞
            System.out.println("result4:" + futureTask2.get());
            
       // FutureTask实现了RunnableFuture接口,RunnableFuture接口继承了Runnable接口,因此可以作为Thread构造参数传入
            new Thread(futureTask2).start();
            // 无返回值,get()会阻塞
            System.out.println("result5:" + futureTask2.get());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
          pool.shutdown();
        }
    }

    static int calcOneToTargetSum(int number) {
        int sum = 0;
        for (int i = 0; i < number; i++) {
            sum += i;
        }
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return sum;
    }

}


Runnable和Callable接口的区别:

  • Runnable定义的方法是run(),而Callable定义的方法是call()
  • Runnable定义的方法是run()无返回值,而Callable定义的方法是call()有返回值
  • Runnable定义的方法是run()不能抛出异常,而Callable定义的方法是call()可以抛出异常
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coo_lw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值