🎯 异步编程四大组件完整关系图
- Runnable/Callable是生成任务,任务submit后得到Future;
- FutureTask顾名思义是Future+Task,既可以作为Task提交,也可作为Future获取结果;
📝 任务定义层
┌─────────────────────────────────────────────────────────┐
│ Runnable → void run() │ 无返回值任务 │
│ Callable<T> → T call() throws Exception │ 有返回值任务 │
└─────────────────────────────────────────────────────────┘
↓ submit()
🚀 执行提交层
┌─────────────────────────────────────────────────────────┐
│ ExecutorService.submit(Runnable) → Future<?> │
│ ExecutorService.submit(Callable<T>) → Future<T> │
└─────────────────────────────────────────────────────────┘
↓ 返回
🔮 结果管理层
┌─────────────────────────────────────────────────────────┐
│ Future<T> → get(), cancel(), isDone(), isCancelled() │
│ FutureTask → Runnable + 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 = 完整的厨师(既知道菜谱,又有餐具,还能决定什么时候做、用什么火候做)