• 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()可以抛出异常
  • 相关阅读:
    FLINK基础(87): DS算子与窗口(1)简介
    Flink实例(三十九):状态管理(十)配置checkpoint
    FLINK基础(112): DS算子与窗口(23)多流转换算子(7)Broadcasting
    Flink实例(三十七):状态管理(八)自定义操作符状态(三)广播状态(Broadcast state)(一) KeyedBroadcastProcessFunction
    Flink实例(三十六):状态管理(七)自定义操作符状态(二)union list state
    关闭firecracker
    Creating Custom rootfs and kernel Images
    Build a single-app rootfs for Firecracker MicroVMs
    由浅入深CrosVM(一)—— 如何在Ubuntu中搭建CrosVM
    Making a Custom MicroVM for AWS Firecracker!
  • 原文地址:https://www.cnblogs.com/lwcode6/p/14803855.html
Copyright © 2020-2023  润新知