当前位置: 首页 > article >正文

【异步编程基础】FutureTask基本原理与异步阻塞问题

文章目录

    • 一、FutureTask 的桥梁作用
    • 二、Future 模式与异步回调
    • 三、 FutureTask获取异步结果的逻辑
      • 1. 获取异步执行结果的步骤
      • 2. 举例说明
      • 3. FutureTask的异步阻塞问题

Runnable 用于定义无返回值的任务,而 Callable 用于定义有返回值的任务。然而,Callable 实例无法直接作为 Thread 线程的 target 目标,因为 Threadtarget 属性类型为 Runnable,而 CallableRunnable 之间没有任何继承关系。那么,如何将 CallableThread 结合使用呢?答案是通过 FutureTask。本文将详细介绍 CallableFutureTask 以及它们在异步编程中的应用。

 

一、FutureTask 的桥梁作用

FutureTaskRunnableFuture 接口的实现类,而 RunnableFuture 继承了 RunnableFuture 接口。因此,FutureTask 既可以作为 Threadtarget,又可以获取异步任务的结果。

如下FutureTask 的核心功能:

//实现了Future:获取异步执行结果
//实现了Runnable:可以作为`Thread` 线程的目标任务。
//支持取消任务、查询任务是否完成等功能。
public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}

public class FutureTask<V> implements RunnableFuture<V> {

以下是一个使用 FutureTask 的示例:

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class FutureTaskExample {
    public static void main(String[] args) throws Exception {
        // 创建 Callable 任务
        Callable<String> callableTask = () -> {
            Thread.sleep(2000); // 模拟耗时操作
            return "Task completed!";
        };

        // 使用 FutureTask 包装 Callable 任务
        FutureTask<String> futureTask = new FutureTask<>(callableTask);

        // 启动一个新线程执行任务
        new Thread(futureTask).start();

        System.out.println("Main thread is doing other work...");

        // 获取任务结果(会阻塞直到任务完成)
        String result = futureTask.get();
        System.out.println("Task result: " + result);
    }
}

Main thread is doing other work...
Task result: Task completed!

 

二、Future 模式与异步回调

Future 模式是一种异步编程模式,其核心思想是:

  • 异步调用:任务提交后立即返回一个 Future 对象,表示任务的未来结果。
  • 结果获取:通过 Future 对象获取任务的执行结果,如果任务未完成,调用线程会阻塞直到任务完成。

Future 接口的核心方法

  • isDone():判断任务是否完成。
  • isCancelled():判断任务是否被取消。
  • cancel(boolean mayInterruptRunning):取消任务的执行。
  • get():获取任务结果(阻塞)。
  • get(long timeout, TimeUnit unit):在指定时间内获取任务结果(超时抛出异常)。

 

三、 FutureTask获取异步结果的逻辑

1. 获取异步执行结果的步骤

通过FutureTask类和Callable接口的联合使用可以创建能获取异步执行结果的线程。

创建能够返回结果的线程,启动并获取结果。具体的步骤介绍如下:

  1. 创建一个Callable接口的实现类,并实现它的call()方法,编写好异步执行的具体逻辑,并且可以有返回值。
  2. 使用Callable实现类的实例构造一个FutureTask实例。
  3. 使用FutureTask实例作为Thread构造器的target入参,构造新的Thread线程实例。
  4. 调用Thread实例的start()方法启动新线程,启动新线程的run()方法并发执行。
  5. 调用FutureTask对象的get()方法阻塞性地获得并发线程的执行结果。

其内部的执行过程为:启动Thread实例的run()方法并发执行后,会执行FutureTask实例的run()方法,最终会并发执行Callable实现类的call()方法。

 

2. 举例说明

使用FutureTask实现异步泡茶喝,main线程可以获取烧水线程、清洗线程的执行结果,然后根据结果判断是否具备泡茶条件,如果具备泡茶条件再泡茶。

在这里插入图片描述

具体代码见:gitee [并发编程] futureTask demo

几点需要注意:

  1. FutureTask和Callable都是泛型类,泛型参数表示返回结果的类型。所以,在使用时它们两个实例的泛型参数需要保持一致。
  2. 通过FutureTask实例的get方法可以获取线程的执行结果,主线程拿到各个线程的结果,然后判断执行。
  3. 主线程阻塞等待。

 

3. FutureTask的异步阻塞问题

虽然FutureTask通过 Future 对象管理异步任务的结果,避免阻塞主线程。但通过FutureTask的get()方法获取异步结果时,主线程也会被阻塞。这一点FutureTask和join是一致的,它们都是异步阻塞模式。

异步阻塞的效率往往比较低,被阻塞的主线程不能干任何事情,唯一能干的就是傻傻等待。原生Java API除了阻塞模式的获取结果外,并没有实现非阻塞的异步结果获取方法。

如果需要用到获取的异步结果,得引入一些额外的框架,比如谷歌的Guava框架。

 


http://www.kler.cn/a/522618.html

相关文章:

  • .NET MAUI 入门学习指南
  • 高级编码参数
  • web集群
  • 创作三载·福启新章2025
  • Android NDK
  • games101-作业2
  • constexpr 实现编译时加密
  • Spark入门(Python)
  • python基础语法(4) ----- 学习笔记分享
  • 基于SpringBoot的网上摄影工作室开发与实现 | 含论文、任务书、选题表
  • 【JavaSE】String类常用字符串方法总结
  • Django-Admin WebView 集成项目技术规范文档 v2.1
  • 【2024年华为OD机试】 (C卷,100分)- 用户调度问题(JavaScriptJava PythonC/C++)
  • games101-(2)线性代数
  • LosslessScaling-学习版[steam价值30元的游戏无损放大/补帧工具]
  • Unexpected WSL error Error code: Wsl/Service/0x8007273的解决
  • 【creo】CREO配置快捷键方式和默认单位
  • DataWhale组队学习 fun-transformer task5
  • 游戏引擎介绍:Game Engine
  • 多维度详细比较 kratos、go-zero、goframe、sponge 框架
  • python3+TensorFlow 2.x 基础学习(一)
  • 在无sudo权限Linux上安装 Ollama 并使用 DeepSeek-R1 模型
  • MongoDB的读写分离技术方案
  • php:代码中怎么搭建一个类似linux系统的crontab服务
  • CICD集合(五):Jenkins+Git+Allure实战(自动化测试)
  • 【elasticsearch】tasks 查看任务