• 【多线程】Callable 接口


    Callable 的用法

    Callable: 一个 interface, 也是创建任务的一个方式, 解决了 Runable 接口不能返回结果的问题
    
    • 1

    代码示例: 创建线程计算 1 + 2 + 3 + … + 1000, 不使用 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();
    }
    
    class Test{
        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
    • 30

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

    代码示例: 创建线程计算 1 + 2 + 3 + … + 1000, 使用 Callable 版本

    • 创建一个匿名内部类, 实现 Callable 接口. Callable 带有泛型参数. 泛型参数表示返回值的类型.
    • 重写 Callable 的 call 方法, 完成累加的过程. 直接通过返回值返回计算结果.
    • 把 callable 实例使用 FutureTask 包装一下.
    • 创建线程, 线程的构造方法传入 FutureTask . 此时新线程就会执行 FutureTask 内部的 Callable 的 call 方法, 完成计算. 计算结果就放到了 FutureTask 对象中.
    • 在主线程中调用 futureTask.get() 能够阻塞等待新线程计算完毕. 并获取到 FutureTask 中的结果.
    class Test{
        public static void main(String[] args) throws 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();
    
            try {
                int result = futureTask.get();
                System.out.println(result);
            } catch (ExecutionException e) {
                throw new RuntimeException(e);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    理解 Callable

    • 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 就可以负责这个等待结果出来的工作, 如果结果没出来就会阻塞等待.

  • 相关阅读:
    vue中websocket使用(客户端)
    【自学开发之旅】Flask-回顾--对象拆分-蓝图(二)
    vmware workstation设置固定ip的几种方法
    MV3D数据预处理流程
    网络安全(黑客)自学
    基于Nodejs的医生预约平台的设计和实现
    2024年最新测评,6款好用的在线代码编辑器推荐
    安全热点|国新办发布《携手构建网络空间命运共同体》白皮书
    【LeetCode】双指针题总结(持续更新)
    win11怎么关闭触控板?win11关闭触控板的三种解决方法
  • 原文地址:https://blog.csdn.net/m0_61832361/article/details/132872571