系列八、Callable接口

一、Callable vs Runnable

(1)Callable接口有返回值,Runnable接口无返回值;

(2)Callable接口会抛异常,Runnable接口不会抛异常;

(3)落地方法不一样,Callable是call,Runnable是run;

二、怎么用

2.1、直接替换Runnable是否可行

不可行。因为Thread类的构造方法根本没有Callable。

2.2、适用场景

这像认识一个不认识的同学,我可以找中间人介绍。

三、FutureTask

3.1、概述

未来的任务,用它干一件事,异步调用。main方法就像一个糖葫芦,一个个方法由main串起来。

问题:解决不了正常调用挂起引起的堵塞问题。

案例:

        (1)老师上着课,口渴了,去买水不合适,讲课线程继续,我可以单起个线程找班长帮忙买水,水买回来了放桌上,我需要的时候再去get;

        (2)4个同学,A计算1+20、B计算21+30、C计算31*到40、D计算41+50,是不是C的计算量有点大啊,FutureTask单起个线程给C计算,我先汇总ABD,最后等C计算完了再汇总

                 C,拿到最终结果;

        (3)高考:会做的先做,不会的放在后面做;

3.2、原理

        在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些任务交给FutureTask对象在后台完成,当主线程将来需要时,就可以通过FutureTask对象获得后台作业的计算结果或者执行状态。一般FutureTask对象多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。
        仅在计算完成时才能检索结果;如果计算尚未完成,则阻塞 get 方法。一旦计算完成,就不能再重新开始或取消计算。get方法而获取结果只有在计算完成时获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或者抛出异常。 
        只计算一次get方法放到最后。

3.3、案例代码

3.3.1、CallableThread

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2023/11/20 16:27
 * @Description: 王五计算21*22*23*...*25
 */
public class CallableThread implements Callable {

    @Override
    public Integer call() throws Exception {
        int sum = 1;
        for (int i = 21; i <= 25; i++) {
            sum *= i;
        }
        Thread.sleep(1);
        return sum;
    }
}

3.3.2、CallableMainApp

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2023/11/20 16:01
 * @Description:
 * 需求描述:
 *      三个同学安排任务如下:
 *          (1)张三计算 1+2+3+...+10
 *          (2)李四计算 11+12+13+...+20
 *          (3)王五计算 21*22*23*...*25
 *      把三个人的计算结果求和,求出总结果
 */
public class CallableMainApp {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask wangwuFutureTask = new FutureTask<>(new CallableThread());

        AtomicReference zhangsanSumResult = new AtomicReference<>(0);
        AtomicReference lisiSumResult = new AtomicReference<>(0);

        /**
         * 张三计算 1+2+3+...+10
         */
        new Thread(() -> {
            try {
                int zhangsanSum = 0;
                for (int i = 1; i <= 10; i++) {
                    zhangsanSum += i;
                }
                zhangsanSumResult.set(zhangsanSum);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "zhangsan").start();

        /**
         * 李四计算 11+12+13+...+20
         */
        new Thread(() -> {
            try {
                int lisiSum = 0;
                for (int i = 11; i <= 20; i++) {
                    lisiSum += i;
                }
                lisiSumResult.set(lisiSum);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "lisi").start();


        /**
         * 王五计算 21*22*23*...*25
         */
        new Thread(wangwuFutureTask, "wangwu").start();

        System.out.println("zhangsanResult = " + zhangsanSumResult.get());
        System.out.println("lisiResult = " + lisiSumResult.get());


        while (!wangwuFutureTask.isDone()) {
            System.out.println("=====================>王五拼命计算中");
        }
        Integer wangwuResult = wangwuFutureTask.get();
        System.out.println("wangwuResult = " + wangwuResult);

        Integer sum = zhangsanSumResult.get() + lisiSumResult.get() + wangwuResult;

        System.out.println("sum = " + sum);
    }

}

 系列八、Callable接口_第1张图片

你可能感兴趣的:(JUC系列,JUC)