多线程的一些基本概念
进程和线程的关系
进程可以认为是运行在电脑上的一个application,而线程则是进程内部的子单元。那么问题来了,单进程的程序可以有多线线程吗?
肯定是可以的,比如如下的代码:
1
2
3
4
5
6
7
8
public class MultiThreadExample {
public static void main(String[] args) {
Thread t1 = new Thread(() -> System.out.println("线程1"));
Thread t2 = new Thread(() -> System.out.println("线程2"));
t1.start();
t2.start();
}
}
JVM就是一个进程,但是其内部可以有多个线程来执行。
并行(Parallelism)和并发(Concurrency)的关系
概念 | 并发(Concurrency) | 并行(Parallelism) |
---|---|---|
核心含义 | 多个任务在同一时间段内交替执行(看起来“同时”) | 多个任务在同一时刻真正同时执行 |
前提条件 | 可以在单核CPU上实现(通过快速切换时间片) | 必须是多核CPU或多处理器才能实现 |
目标 | 提高系统的响应速度(让多个任务都能被处理) | 提高执行效率(让任务真的同时做) |
体现 | “宏观同时,微观交替” | “微观同时” |
关键字 | 任务管理、调度 | 真正的物理同时执行 |
总结:并行是真正的同时进行,而并发只是从宏观上来看是同时进行的。
用户线程(greenThread)和内核线程(nativeThread)
用户线程只是java 自己创建额线程,这个线程其实是不能直接来执行任务的。
内核线程是真正来执行任务的线程,用户线程和内核线程是有映射关系的,比如 java 的是 1:1 映射的,java 创建一个线程就需要映射一个内核线程。换句话说真正执行任务的其实是内核线程。内核线程是操作系统级别的。
对比点 | 用户线程(User Thread) | 内核线程(Kernel Thread) |
---|---|---|
管理者 | 用户空间的线程库(比如 libpthread ) |
操作系统内核 |
上下文切换 | 发生在用户空间,速度快(不需要系统调用) | 需要切换到内核态,速度慢 |
并发性 | 在多核 CPU 上通常不能真正并行(除非映射到多个内核线程) | 可以利用多核 CPU 真正并行执行 |
阻塞影响 | 一个线程阻塞可能导致整个进程都挂起(因为内核只看到一个线程) | 一个线程阻塞不会影响其他线程 |
资源开销 | 小,创建和切换成本低 | 大,线程控制块、栈等资源都由内核维护 |
1:1的映射模型劣势非常的大,因为每个线程占用内存大约 1M,这就导致假如有 1000 个线程,那么就会消耗 1G 的内存。所以现在很多语言都发明了协程这个概念:
使用几百万个虚拟线程来复用几十个内核线程,从而实现高并发+低开销。
比如 java21 中也引入vitual thead 虚拟线程。