• 【JavaEE初阶】 Callable 接口


    🌴Callable 接口

    🚩Callable 的用法

    Callable 是一个 interface . 相当于把线程封装了一个 “返回值”. 方便程序猿借助多线程的方式计算结果

    比如我们有以下需求

    创建线程计算 1 + 2 + 3 + … + 1000, 如果我们不使用 Callable

    不使用 Callable的实现过程如下:

    • 建一个类 Result , 包含一个 sum 表示最终结果, lock 表示线程同步使用的锁对象.

    • main 方法中先创建 Result 实例, 然后创建一个线程 t. 在线程内部计算 1 + 2 + 3 + … + 1000.

    • 主线程同时使用 wait 等待线程 t 计算结束. (注意, 如果执行到 wait 之前, 线程 t 已经计算完了, 就不必等待了).

    • 当线程 t 计算完毕后, 通过 notify 唤醒主线程, 主线程再打印结果

    代码实现如下:

    class Result {
        public int sum = 0;
        public Object lock = new Object();
    }
    public class ThreadDemo1 {
        public static void main(String[] args) throws InterruptedException {
            Result result = new Result();
            Thread t = new Thread() {
                @Override
                public void run() {
                    int sum = 0;
                    for (int i = 1; i <= 1000; i++) {
                        sum += i;
                    }
                    synchronized (result.lock) {
                        result.sum = sum;
                        result.lock.notify();
                    }
                }
            };
            t.start();
            synchronized (result.lock) {
                while (result.sum == 0) {
                    result.lock.wait();
                }
                System.out.println(result.sum);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    可以看到, 上述代码需要一个辅助类 Result, 还需要使用一系列的加锁和 wait notify 操作, 代码复杂, 容易出错.

    接下来我们再使用 Callable接口进行实现一下

    使用 Callable的实现过程如下:

    • 创建一个匿名内部类, 实现 Callable 接口. Callable 带有泛型参数. 泛型参数表示返回值的类型.

    • 重写 Callable 的 call 方法, 完成累加的过程. 直接通过返回值返回计算结果.

    • 把 callable 实例使用 FutureTask 包装一下.

    • 创建线程, 线程的构造方法传入 FutureTask . 此时新线程就会执行 FutureTask 内部的 Callable 的call 方法, 完成计算. 计算结果就放到了 FutureTask 对象中.

    • 在主线程中调用 futureTask.get() 能够阻塞等待新线程计算完毕. 并获取到 FutureTask 中的结果

    代码实现如下:

    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    public class ThreadDemo2 {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            Callable<Integer> callable = new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    int sum = 0;
                    for (int i = 1; i <= 1000; i++) {
                        sum += i;
                    }
                    return sum;
                }
            };
            FutureTask<Integer> futureTask = new FutureTask<>(callable);
            Thread t = new Thread(futureTask);
            t.start();
            int result = futureTask.get();
            System.out.println(result);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    我们可以看到, 使用 Callable 和 FutureTask 之后, 代码简化了很多, 也不必手动写线程同步代码了

    其中上述代码代表的一些含义为:

    • Callable 和 Runnable 相对, 都是描述一个 “任务”. Callable 描述的是带有返回值的任务,

    • Runnable 描述的是不带返回值的任务.

    • Callable 通常需要搭配 FutureTask 来使用. FutureTask 用来保存 Callable 的返回结果. 因为

    • Callable 往往是在另一个线程中执行的, 啥时候执行完并不确定.

    • FutureTask 就可以负责这个等待结果出来的工作

    这里博主有一个例子可以更好的理解理解 FutureTask

    我们可以想象去吃麻辣烫. 当餐点好后, 后厨就开始做了. 同时前台会给你一张 “小票” . 这个小票就是FutureTask. 后面我们可以随时凭这张小票去查看自己的这份麻辣烫做出来了没

    🎄相关面试题

    介绍下 Callable 是什么

    • Callable 是一个 interface . 相当于把线程封装了一个 “返回值”. 方便程序猿借助多线程的方式计算
      结果.
    • Callable 和 Runnable 相对, 都是描述一个 “任务”.
    • Callable 描述的是带有返回值的任务, Runnable 描述的是不带返回值的任务
    • Callable 通常需要搭配 FutureTask 来使用. FutureTask 用来保存 Callable 的返回结果. 因为Callable 往往是在另一个线程中执行的, 啥时候执行完并不确定.FutureTask 就可以负责这个等待结果出来的工作.

    ⭕总结

    关于《【JavaEE初阶】 Callable 接口》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!

  • 相关阅读:
    变种水仙花C,超详细思路+源代码
    Vue学习之--------el与data的两种写法、MVVM模型、数据代理(2022/7/5)
    Failed to start mysql.service Unit mysql.service not found
    【逐步剖C++】-第一章-C++类和对象(上)
    第一章 信息化和信息系统
    轨迹规划 | 图解路径跟踪PID算法(附ROS C++/Python/Matlab仿真)
    什么是Fetch API?与传统的AJAX相比,有什么优势?
    VMware ESXi 8.0 SLIC 2.6 & macOS Unlocker (Oct 2022 GA)
    条款41:针对可复制的形参,在移动成本低并且一定会被复制的前提下,考虑将其按值传递
    linux c++ 开发 tensorrt 安装
  • 原文地址:https://blog.csdn.net/m0_71731682/article/details/134063399