异步编程四大组件

145 阅读3分钟

🎯 异步编程四大组件完整关系图

  • Runnable/Callable是生成任务,任务submit后得到Future;
  • FutureTask顾名思义是Future+Task,既可以作为Task提交,也可作为Future获取结果;
📝 任务定义层
┌─────────────────────────────────────────────────────────┐
│ Runnablevoid run()                  │ 无返回值任务  │
│ Callable<T> → T call() throws Exception   │ 有返回值任务  │
└─────────────────────────────────────────────────────────┘
                           ↓ submit()
🚀 执行提交层
┌─────────────────────────────────────────────────────────┐
│ ExecutorService.submit(Runnable)    → Future<?>         │
│ ExecutorService.submit(Callable<T>) → Future<T>         │
└─────────────────────────────────────────────────────────┘
                           ↓ 返回
🔮 结果管理层
┌─────────────────────────────────────────────────────────┐
│ Future<T>   → get(), cancel(), isDone(), isCancelled()  │
│ FutureTaskRunnable + Future 的完美结合                │
└─────────────────────────────────────────────────────────┘

线程是一个独立的执行单元,可以被操作系统调度;而线程体仅仅只是一个任务,就类似于一段普通的代码,需要线程作为载体才能运行,ChatGPT给出的总结特别对:线程是执行线程体的容器,线程体是一个可运行的任务

不过Java中创建线程体的方式,可以基于Runnable创建,也可以靠Callable创建带返回的、也可以通过Timer创建支持定时的……,但不管是哪种方式,到最后都是依赖于Runnable这个类实现的,如果大家有去研究过Callable的原理,大家就会发现:Callable实际上就是Runnable的封装体

相关文章:

四大组件Demo

import java.util.concurrent.*;

/**
 * 🎯 异步编程四大组件综合演示
 * Runnable、Callable、Future、FutureTask 完整对比
 */
public class ComprehensiveAsyncDemo {

    public static void main(String[] args) throws Exception {

        ExecutorService executor = Executors.newFixedThreadPool(4);

        basicConceptsDemo(executor);

        executor.shutdown();
    }

    // 基础概念演示
    static void basicConceptsDemo(ExecutorService executor) throws Exception {
        System.out.println("🔍 四大组件基础演示:\n");

        // ========== 1. Runnable 演示 ==========
        System.out.println("1️⃣ Runnable - 无返回值任务");
        System.out.println("   特点:void run(),无返回值,不能抛出检查异常");

        Runnable runnableTask = () -> {
            System.out.println("   🏃‍♂️ Runnable 执行中,线程:" + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            System.out.println("   ✅ Runnable 执行完成");
        };

        // 提交 Runnable,返回 Future<?>
        Future<?> runnableFuture = executor.submit(runnableTask);
        Object runnableResult = runnableFuture.get(); // 返回 null
        System.out.println("   📋 Runnable 结果:" + runnableResult + " (总是null)\n");

        // ========== 2. Callable 演示 ==========
        System.out.println("2️⃣ Callable - 有返回值任务");
        System.out.println("   特点:T call() throws Exception,有返回值,可抛出异常");

        Callable<String> callableTask = () -> {
            System.out.println("   📞 Callable 执行中,线程:" + Thread.currentThread().getName());
            Thread.sleep(1000);
            return "Callable 计算结果:42";
        };

        // 提交 Callable,返回 Future<T>
        Future<String> callableFuture = executor.submit(callableTask);
        String callableResult = callableFuture.get(); // 返回实际结果
        System.out.println("   📋 Callable 结果:" + callableResult + "\n");

        // ========== 3. Future 演示 ==========
        System.out.println("3️⃣ Future - 异步结果管理器");
        System.out.println("   特点:管理异步任务,获取结果,控制执行");

        Future<Integer> mathFuture = executor.submit(() -> {
            System.out.println("   🔮 Future 管理的任务执行中...");
            Thread.sleep(1500);
            return 100 + 200;
        });

        // Future 的各种方法
        System.out.println("   🔍 任务是否完成:" + mathFuture.isDone());
        System.out.println("   🔍 任务是否取消:" + mathFuture.isCancelled());

        Integer mathResult = mathFuture.get();
        System.out.println("   📋 Future 管理的结果:" + mathResult);
        System.out.println("   🔍 任务完成后状态:" + mathFuture.isDone() + "\n");

        // ========== 4. FutureTask 演示 ==========
        System.out.println("4️⃣ FutureTask - Runnable + Future 的结合体");
        System.out.println("   特点:既可执行又可管理结果,最灵活");

        // 基于 Callable 创建 FutureTask
        FutureTask<String> futureTask = new FutureTask<>(() -> {
            System.out.println("   🎯 FutureTask 执行中,线程:" + Thread.currentThread().getName());
            Thread.sleep(1000);
            return "FutureTask 执行结果";
        });

        System.out.println("   🔍 FutureTask 是 Runnable:" + (futureTask instanceof Runnable));
        System.out.println("   🔍 FutureTask 是 Future:" + (futureTask instanceof Future));

        // 可以作为 Runnable 提交
        executor.submit(futureTask);

        // 可以作为 Future 获取结果
        String futureTaskResult = futureTask.get();
        System.out.println("   📋 FutureTask 结果:" + futureTaskResult);
    }


}

FutureTask 的核心作用

📝 传统方式的流程

Runnable/Callable → submit() → Future
     ↓                ↓         ↓
   定义任务         立即执行    管理结果

问题:创建任务 = 立即执行,无法控制执行时机和方式

🚀 FutureTask 的创新

FutureTask = 任务容器 + 执行器 + 结果管理器
     ↓
  创建 ≠ 执行
     ↓
可以选择何时执行、如何执行

🔥 FutureTask 解决的核心问题

1. 任务定义和执行分离

// ❌ 传统方式:创建即执行
Future<String> future = executor.submit(() -> "任务");  // 立即执行

// ✅ FutureTask:创建不执行
FutureTask<String> task = new FutureTask<>(() -> "任务");  // 只是创建
// ... 可以等待合适的时机再执行
executor.submit(task);  // 选择执行时机

2. 执行方式的灵活选择

FutureTask<String> task = new FutureTask<>(() -> "任务");

// 可以选择不同的执行方式:
executor.submit(task);        // 线程池执行
new Thread(task).start();     // 独立线程执行  
task.run();                   // 当前线程执行

3. 任务的预定义和复用

// 预先定义多个任务
FutureTask<String> dbTask = new FutureTask<>(() -> "查数据库");
FutureTask<String> cacheTask = new FutureTask<>(() -> "查缓存");

// 根据条件选择执行
if (needDatabase) {
    executor.submit(dbTask);
}
if (needCache) {
    executor.submit(cacheTask);
}

💡 FutureTask 的本质

FutureTask 把任务变成了一个"对象"

  • Runnable/Callable - 只是方法,定义了"做什么"
  • Future - 只是结果容器,管理"做得怎么样"
  • FutureTask - 是完整的任务对象,控制"什么时候做"和"怎么做"

🎯 简单类比

想象你要做饭:

  • Runnable/Callable = 菜谱(定义怎么做菜)
  • Future = 餐具(用来盛菜的容器)
  • FutureTask = 完整的厨师(既知道菜谱,又有餐具,还能决定什么时候做、用什么火候做)