🌴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); } } }
可以看到, 上述代码需要一个辅助类 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); } }
我们可以看到, 使用 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 接口》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!