进程、线程、协程
进程(Process)
一、是什么?
进程是操作系统分配资源的基本单位,表示一个正在执行的程序实例。每个进程拥有独立的内存空间(代码段、数据段、堆栈等)、文件句柄和系统资源。例如:运行中的Chrome浏览器是一个进程。
二、解决什么问题
解决程序间的隔离性和资源分配问题:
- 防止程序间相互干扰(如一个程序崩溃不影响其他程序)
- 实现多任务并行(如同时运行IDE和音乐播放器)
- 提供安全边界(操作系统级权限控制)
三、核心方法(Java)
- 创建进程:
ProcessBuilder.start()
或Runtime.exec()
- 等待进程:
Process.waitFor()
- 销毁进程:
Process.destroy()
四、核心状态
- 创建(New):进程正在被初始化。
- 就绪(Ready):等待CPU调度执行。
- 运行(Running):正在CPU上执行。
- 阻塞(Blocked):等待I/O等事件(如读取文件)。
- 终止(Terminated):执行完毕或被强制结束。
五、应用场景
- 启动外部程序(如调用系统命令)
- 需要强隔离的独立应用(如数据库服务)
- 微服务架构中的服务实例
六、Java示例
java
// 启动记事本进程
ProcessBuilder builder = new ProcessBuilder("notepad.exe");
Process process = builder.start();
process.waitFor(); // 等待进程结束
System.out.println("记事本已关闭");
七、重要注意事项
- 进程创建/销毁开销大(需分配独立内存)
- 进程间通信(IPC)复杂(需管道、Socket等)
- 一个Java程序默认至少一个进程(JVM进程)
线程(Thread)
一、是什么?
线程是CPU调度的最小单位,属于进程内的执行流。一个进程可包含多个线程,共享进程的内存空间(如堆内存),但拥有独立的栈和程序计数器。
二、解决什么问题
解决进程内并发执行效率问题:
- 减少上下文切换开销(线程切换比进程快5-10倍)
- 共享内存简化通信(无需IPC)
- 充分利用多核CPU(并行计算)
三、核心方法(Java)
- 创建线程:
new Thread(Runnable).start()
- 线程池:
Executors.newFixedThreadPool()
- 同步:
synchronized
、ReentrantLock
- 协作:
wait()
/notify()
、CountDownLatch
四、核心状态(Java线程)
- NEW:通过
new Thread()
创建但未启动。 - RUNNABLE:调用
start()
后,等待或正在运行。 - BLOCKED:等待监视器锁(如
synchronized
)。 - WAITING:无期限等待(如
object.wait()
)。 - TIMED_WAITING:有限等待(如
Thread.sleep(1000)
)。 - TERMINATED:执行完毕。
五、应用场景
- 高并发服务器(如Tomcat处理请求)
- 异步任务(如后台日志写入)
- 实时数据处理(如股票行情分析)
六、Java示例
java
// 多线程下载文件
ExecutorService executor = Executors.newFixedThreadPool(3);
List<Future<String>> results = new ArrayList<>();
for (String url : urls) {
results.add(executor.submit(() -> {
return downloadFile(url); // 每个线程下载一个文件
}));
}
// 获取结果
for (Future<String> future : results) {
System.out.println(future.get());
}
executor.shutdown();
七、重要注意事项
- 需处理线程安全(竞态条件、死锁)
- 线程数过多导致上下文切换开销增加
- Java线程与OS线程1:1对应(重量级)
协程(Coroutine) - Java虚拟线程(JDK19+)
一、是什么?
协程是用户态轻量级线程,由程序而非OS调度。Java中称为虚拟线程(Virtual Thread),通过Project Loom实现(JDK19+正式发布)。特点:
- 在用户空间调度(无OS上下文切换)
- 挂起/恢复由JVM控制
- 1个OS线程可运行数千个协程
二、解决什么问题
解决传统线程的高并发瓶颈:
- 消除线程数限制(可创建百万级虚拟线程)
- 减少内存占用(初始栈仅4KB vs 线程1MB)
- 降低I/O阻塞成本(挂起时不占用OS线程)
三、核心方法(Java)
- 启动虚拟线程:
Thread.startVirtualThread()
- 虚拟线程池:
Executors.newVirtualThreadPerTaskExecutor()
- 挂起/恢复:自动处理(无需手动)
四、核心状态
协程状态对开发者透明,由JVM管理。本质分为:
- 运行中:占用载体线程执行。
- 挂起(Yield):遇到I/O时主动让出CPU(如
Files.readString()
)。 - 结束:任务完成。
五、应用场景
- 超高并发服务(10K+连接)
- I/O密集型任务(如微服务网关)
- 响应式编程(替代回调地狱)
六、Java示例(JDK21+)
java
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i -> {
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(1));
System.out.println("Task " + i + " on virtual thread");
return i;
});
});
} // 自动关闭executor
七、重要注意事项
- CPU密集型任务无优势(仍需要平台线程)
synchronized
会阻塞载体线程(优先用ReentrantLock
)- 调试工具需升级(如支持虚拟线程的调试器)
核心区别
特性 | 进程 | 线程 | 协程(虚拟线程) |
---|---|---|---|
隔离性 | 完全隔离(独立内存) | 共享内存 | 共享内存 |
创建数量 | 数百个 | 数千个 | 百万级 |
内存开销 | 高(MB级) | 中(MB级) | 极低(KB级) |
切换开销 | 高(OS内核切换) | 中(OS内核切换) | 低(用户态切换) |
调度方 | 操作系统 | 操作系统 | JVM(用户空间) |
通信成本 | 高(IPC) | 中(需同步) | 低(无同步需求) |
最佳场景 | 强隔离任务 | CPU密集型任务 | I/O密集型高并发 |
总结
- 进程:资源隔离的基石,适合独立应用
- 线程:并发编程主力,平衡性能与开发成本
- 协程(虚拟线程):JDK19+的革命性特性,突破高并发瓶颈
- 核心价值:用同步代码写异步逻辑,资源利用率提升10倍+
- 使用建议:
- 新项目优先用虚拟线程(
Executors.newVirtualThreadPerTaskExecutor()
) - 替换
ThreadPoolExecutor
处理I/O任务 - 避免在虚拟线程中使用
synchronized
- 新项目优先用虚拟线程(
演进趋势:Java正从"线程池+回调"转向虚拟线程+结构化并发(JDK21)。学习建议:掌握传统线程模型,同时拥抱虚拟线程的轻量化优势。