05. 异步线程创建-Callable 方式

java 多线程系列文章列表, 请查看目录: 《java 多线程学习笔记》

1. Callable 方式

Callable 方式最主要的特点就是可以阻塞式获取子线程执行结果, 也就是说对于长耗时的任务,可以放到子线程中执行, 而主线程去执行其它任务. 当主线程执行完其它任务之后, 需要获取子线程任务返回结果时, 如果子线程没有执行完, 主线程会阻塞, 等子线程执行完之后, 再继续执行.

1.1 Callable 特点

  • 面向接口编程, 松耦合设计
  • 在多线程模式下,可实现对象资源共享. 但是需要注意使用原子类变量AtomicXXX
  • 不能独立运行, 需绑定在Thread实例上运行
  • 有返回值, 主线程可等待异步线程执行结果, 可捕获异步线程异常

1.2 使用步骤

  1. 自定义Callable 子类, 并创建子类实例. 可使用普通类, 匿名内部类, lambda 表达式等方式
  2. 创建异步任务, Future 接口实例
  3. 创建线程, 绑定Future任务, 并启动异步线程
  4. 阻塞获取异步线程结果

1.3 适用场景

  • 主线程需要等待异步任务执行结束时
  • 主线程获取异步任务执行结果时
  • 主线程需要捕获异步线程异常时
  • 主线程需要

1.4 Future API

方法签名 方法描述 参数
boolean cancel(boolean mayInterruptIfRunning) 取消异步任务. 如过正在运行, 是否强制取消
boolean isCancelled() 子线程是否被取消
boolean isDone() 子线程是否结束, 子线程被取消也会返回true
V get() 获取异步线程返回结果, 如果线程被取消或执行过程抛出异常, 则会抛出异常
V get(long timeout, TimeUnit unit) 获取异步线程返回结果, 指定阻塞时间, 超时抛出异常 阻塞等待时间

2. 场景示例

2.1 主线程等待异步线程结束

  • 异步线程执行长耗时任务时, 主线程不阻塞, 继续执行任务
  • 主线程获取异步线程执行结果时, 如果异步线程未结束或进行阻塞
  • 异步线程执行过程抛出异常时, 主线程可在获取异步线程执行结果时捕获
public static void main(String[] args){

    // 1. 创建Callable 实例
    Callable callable =new Callable<String>(){
        public String call() throws Exception {
            String time = Thread.currentThread().getName() + "-" + LocalDateTime.now().toString();

            Thread.sleep(5000);

            System.out.println("子线程计算完毕:" + time);
            return time;
        }
    };

    // 2. 创建异步任务
    FutureTask<String> future = new FutureTask<>(callable);

    // 3. 创建线程并绑定异步任务
    Thread thread = new Thread(future);

    // 4. 启动异步线程
    thread.start();

    // 5. 主线程无阻塞继续执行任务
    System.out.println("主线程执行其它任务...");

    // 6. 阻塞获取异步任务结果
    try {
        String result = future.get();
        System.out.println("result:" + result);
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }

}

2.2 主线程捕获异步线程异常

主线程在获取异步线程执行结果时, 会捕获到异步线程的异常

public static void main(String[] args){

    // 1. 创建Callable 实例
    Callable callable =new Callable<String>(){
        public String call() throws Exception {
            // 抛出异常
            int a = 1/0;
            return null;
        }
    };

    // 2. 创建异步任务
    FutureTask<String> future = new FutureTask<>(callable);

    // 3. 创建线程并绑定异步任务
    Thread thread = new Thread(future);

    // 4. 启动异步线程
    thread.start();

    // 5. 阻塞获取异步任务结果
    try {
        String result = future.get();
        System.out.println("result:" + result);
    } catch (InterruptedException | ExecutionException e) {
        System.out.println("主线程捕获到子线程异常: " + e.getMessage());
    }

}

2.3 主线程取消异步线程

  • 当异步线程正在执行时, 主线程可主动取消异步任务.
  • 取消任务时如果设置为true, 则表示强制取消, 无论异步任务是否在运行. 如果设置为false, 则表示如果异步任务已经开始运行,则不进行取消.
public static void main(String[] args) throws InterruptedException {

    // 1. 创建Callable 实例
    Callable callable =new Callable<String>(){
        public String call() throws Exception {
            String time = Thread.currentThread().getName() + "-" + LocalDateTime.now().toString();

            Thread.sleep(5000);

            System.out.println("子线程计算完毕:" + time);
            return time;
        }
    };

    // 2. 创建异步任务
    FutureTask<String> future = new FutureTask<>(callable);

    // 3. 创建线程并绑定异步任务
    Thread thread = new Thread(future);

    // 4. 启动异步线程
    thread.start();

    // 5. 主线程无阻塞继续执行任务
    System.out.println("主线程执行其它任务...");

    // 休眠2秒
    Thread.sleep(2000l);

    // 强制结束异步线程
    future.cancel(true);

    // 6. 阻塞获取异步任务结果
    try {
        String result = future.get();
        System.out.println("result:" + result);
    } catch (Exception e) {
        System.out.println("主线程捕获到异步线程异常: " + e.getMessage());
        System.out.println("异步线程: isDone:" + future.isDone() + ", isCancle:" + future.isCancelled());
        e.printStackTrace();
    }

}

发布了321 篇原创文章 · 获赞 676 · 访问量 147万+

猜你喜欢

转载自blog.csdn.net/zongf0504/article/details/100186117