• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

JavaEE(系列14) -- 多线程(Callable)

武飞扬头像
哈士奇的奥利奥
帮助1

Callable接口

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

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

思路:

  1. 创建一个类Result,包含 sum 表示最终结果, lock 表示线程同步使用的锁对象.
  2. main 方法中先创建 Result 实例, 然后创建一个线程 t. 在线程内部计算 1 2 3 ... 1000.
  3. 主线程同时使用 wait 等待线程 t 计算结束. (注意, 如果执行到 wait 之前, 线程 t 已经计算完了, 就不必等待了).
  4. 当线程 t 计算完毕后, 通过 notify 唤醒主线程, 主线程再打印结果.
  1.  
    static class Result {
  2.  
      public int sum = 0;
  3.  
      public Object lock = new Object();
  4.  
    }
  5.  
     
  6.  
     
  7.  
    public static void main(String[] args) throws InterruptedException {
  8.  
      Result result = new Result();
  9.  
      Thread t = new Thread() {
  10.  
        @Override
  11.  
        public void run() {
  12.  
          int sum = 0;
  13.  
          for (int i = 1; i <= 1000; i ) {
  14.  
            sum = i;
  15.  
         }
  16.  
          synchronized (result.lock) {
  17.  
            result.sum = sum;
  18.  
            result.lock.notify();
  19.  
         }
  20.  
       }
  21.  
     };
  22.  
      t.start();
  23.  
      synchronized (result.lock) {
  24.  
        while (result.sum == 0) {
  25.  
          result.lock.wait();
  26.  
       }
  27.  
        System.out.println(result.sum);
  28.  
     }
  29.  
    }
学新通

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

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

思路:

  • 创建一个匿名内部类, 实现 Callable 接口. Callable 带有泛型参数. 泛型参数表示返回值的类型.
  • 重写 Callable 的 call 方法, 完成累加的过程. 直接通过返回值返回计算结果.
  • callable 实例使用 FutureTask 包装一下.
  • 创建线程, 线程的构造方法传入 FutureTask . 此时新线程就会执行 FutureTask 内部的 Callable 的call 方法, 完成计算. 计算结果就放到了 FutureTask 对象中.
  • 在主线程中调用 futureTask.get() 能够阻塞等待新线程计算完毕. 并获取到 FutureTask 中的结果.
  1.  
    package JUC;
  2.  
     
  3.  
    import java.util.concurrent.Callable;
  4.  
    import java.util.concurrent.ExecutionException;
  5.  
    import java.util.concurrent.FutureTask;
  6.  
     
  7.  
     
  8.  
    public class callableTest {
  9.  
    public static void main(String[] args) throws ExecutionException, InterruptedException {
  10.  
    Callable<Integer> callable = new Callable<Integer>() {
  11.  
    @Override
  12.  
    public Integer call() throws Exception {
  13.  
    int sum = 0;
  14.  
    for (int i = 0; i < 1000; i ) {
  15.  
    sum = i;
  16.  
    }
  17.  
    return sum;
  18.  
    }
  19.  
    };
  20.  
     
  21.  
    // 需要找一个人,来完成这个任务(需要线程去执行)
  22.  
    // 在执行之前要进行一个包装,传入线程,启动任务
  23.  
    FutureTask<Integer> futureTask = new FutureTask<>(callable);
  24.  
    Thread t = new Thread(futureTask);
  25.  
    t.start();
  26.  
     
  27.  
    // 获取上面t线程任务的返回值
  28.  
    System.out.println(futureTask.get());
  29.  
    }
  30.  
    }
学新通

 问题:我们可以发现,我们是在主线程中进行调用的get方法,那么如何保证在调用get之前,call方法就是执行完毕的了呢?


 答案: futureTask 的 get方法和join方法是类似的,都是会堵塞等待的,等待call方法执行完毕,get方法再进行返回call方法的返回值.

 理解Callable和FutureTask

理解 Callable

        Callable 和 Runnable 相对, 都是描述一个 "任务". Callable 描述的是带有返回值的任务,Runnable 描述的是不带返回值的任务.
Callable 通常需要搭配 FutureTask 来使用. FutureTask 用来保存 Callable 的返回结果. 因为Callable 往往是在另一个线程中执行的, 啥时候执行完并不确定.FutureTask 就可以负责这个等待结果出来的工作.

理解 FutureTask 

 

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

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgejfci
系列文章
更多 icon
同类精品
更多 icon
继续加载