java 深入剖析FutureTask

java 深入剖析FutureTask

2020-06-24 21:42:03发布 浏览数:617
概述:java 深入剖析FutureTask

文章目录

FutureTask介绍如何使用 FutureTask“烧水泡茶”程序

FutureTask介绍

首先来看下FutureTask的关系图,了解下是什么

类关系图在IDEA中的快捷键为Ctrl+Alt+U


由上图可以看出FutureTask实现了RunnableFuture接口,RunnableFuture接口又继承了Future接口和Runnable接口(Runnable函数式接口)

接下来看下Future接口的方法

取消任务:boolean cancel(boolean mayInterruptIfRunning);

判断任务是否取消:boolean isCancelled();

判断任务是否结束boolean isDone();

获取任务返回值V get() throws InterruptedException, ExecutionException;

获取任务返回值(支持超时)V get(long timeout, TimeUnit unit) throws InterruptedException,ExecutionException, TimeoutException;

再来看下Runnable接口的方法

public abstract void run();
1

最后来看下FutureTask接口构造方法

FutureTask(Callable<V> callable) FutureTask(Runnable runnable, V result)

如何使用 FutureTask

其实很简单,FutureTask 实现了 Runnable 和 Future 接口,由于实现了 Runnable 接口,所以可以将 FutureTask 对象作为任务提交给 ThreadPoolExecutor 去执行,也可以直接被 Thread 执行;又因为实现了 Future 接口,所以也能用来获得任务的执行结果。

为什么可以将 FutureTask 对象作为任务提交给 ThreadPoolExecutor 去执行呢?


可以看到ThreadPoolExecutor是ExecutorService的实现类,最终会将FutureTask提交给ThreadPoolExecutor

为什么可以直接被Thread执行呢?

Thread源码如下:

public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
123

会将FutureTask任务提交给target对象

下面的示例代码是将 FutureTask 对象提交给 ThreadPoolExecutor 去执行。

import java.util.concurrent.*;

public class FutureTaskDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建任务
        FutureTask<Integer> futureTask = new FutureTask<>(() -> 1 + 2);
        //创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(1);
        //执行任务
        executor.submit(futureTask);
        //获取任务的执行结果
        Integer integer = futureTask.get();
        System.out.println(integer); //结果为3

    }
}
123456789101112131415161718

FutureTask 对象直接被 Thread 执行的示例代码如下所示。相信你已经发现了,利用 FutureTask 对象可以很容易获取子线程的执行结果

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;


public class FutureTaskDemo2 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建任务
        FutureTask<Integer> futureTask = new FutureTask<>(() -> 1 + 2);
        //创建线程,将任务提交给target
        Thread t = new Thread(futureTask);
        //启动线程
        t.start();
        //获取任务的执行结果
        Integer integer = futureTask.get();
        System.out.println(integer); //结果为3
    }
}
123456789101112131415161718

“烧水泡茶”程序

假设线程T1执行洗水壶烧开水泡茶线程T2执行洗茶壶洗茶杯拿茶叶。需要注意的是线程T1的泡茶任务需要等线程T2拿到茶叶后才能执行泡茶操作。


首先,我们创建了两个 FutureTask——f1 和 f2f1 完成洗水壶烧开水泡茶的任务,f2 完成洗茶壶洗茶杯拿茶叶的任务;这里需要注意的是 f1 这个任务在执行泡茶任务前,需要等待 f2 把茶叶拿来,所以 f1 内部需要引用 f2,并在执行泡茶之前,调用 f2 的 get() 方法实现等待。

import java.util.concurrent.*;


public class FutureTaskDemo3 {

    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建T2的任务f2
        FutureTask<String> f2 = new FutureTask<>(new T2Task());
        //创建T1的任务f1
        FutureTask<String> f1 = new FutureTask<>(new T1Task(f2));
        //创建线程T1,执行f1任务
        Thread T1 = new Thread(f1);
        //创建线程T2,执行f2任务
        Thread T2 = new Thread(f2);
        T1.start();
        T2.start();
        System.out.println(f1.get());
        System.out.println("终于开始喝茶了");

    }


    static class T1Task implements Callable<String> {
        FutureTask<String> futureTask;

        T1Task(FutureTask<String> t) {
            this.futureTask = t;
        }

        @Override
        public String call() throws Exception {
            //洗水壶
            System.out.println("洗水壶。。。");
            Thread.sleep(1000);
            //烧开水
            System.out.println("烧开水。。。");
            Thread.sleep(15000);
            System.out.println("线程T1正在获取线程T2拿到的茶叶");
            //获取T2线程的茶叶
            String s = futureTask.get();
            //泡茶
            return "上茶:" + s;
        }
    }


    static class T2Task implements Callable<String> {
        @Override
        public String call() throws Exception {
            //洗茶壶
            System.out.println("洗茶壶。。。");
            Thread.sleep(1000);
            //洗茶杯
            System.out.println("洗茶杯。。。");
            Thread.sleep(2000);
            //拿茶叶
            System.out.println("拿茶叶。。。");
            Thread.sleep(1000);
            return "龙井";
        }
    }


}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970

结果

开心一刻

一学生上课时老想打球,眼睛不住地往操场上盯,老师批语他说:“你呀,人在教室,心在操场,这怎么行呢?”学生听了说道 :“老师,让我人去操场,把心留在教室,好吗?”


详细请看王宝令老师:https://time.geekbang.org/column/article/91292

如有不对的地方,还请指正,博主会及时更改!

如果帮到你了,还请点个赞哈!

请先
登录
后评论
0 条评论
暂时没有评论
最新文章
更多