Java并发编程理解01:对进程和线程的初步概念理解

进程和线程

进程

我们平时说的应用程序(App)本质上是由指令和数据组成的静态文件,就像存在硬盘、U 盘或网盘里的 “静止代码”。当我们双击打开一个 App 时,这些原本 “沉睡” 的代码会经历一个关键转变:程序的指令会被加载到 CPU 执行,数据会被调入内存供程序读写,同时还可能需要调用磁盘、网络等设备资源 —— 这个正在 “活动” 的程序实例,就是操作系统视角下的 “进程”。

简单来说,进程可以看作程序的 “动态化身”。比如你打开一次记事本,就生成一个记事本进程;再开一个新的记事本窗口,就会创建第二个进程(同一程序的多个实例)。但有些程序比较特殊,比如网易云音乐,每次启动只会存在一个进程,不允许同时运行多个相同实例。这种差异体现了进程的动态特性 —— 程序是磁盘上的静态文件,而进程是程序在内存中运行的 “活的状态”,包含了代码执行、数据交互和资源管理的全过程。

从操作系统的资源管理角度看,进程是分配资源的最小单位(尤其是内存资源)。它负责管理程序运行所需的一切:把代码从磁盘读入内存,为数据分配存储区域,协调 CPU 执行指令的顺序,还要处理网络请求、文件读写等输入输出操作。进程又分为两类:系统进程是操作系统自身的 “后台助手”,比如负责内存管理、设备驱动的进程,它们随系统启动而运行;用户进程则是我们主动启动的程序,比如浏览器、游戏、文档编辑器等,这些进程的生命周期由用户操作触发。

线程

当我们的电脑同时运行着几十上百个程序时,CPU 却只有几个核心,如何让这些程序看起来 “同时运行”?这就需要 CPU 调度机制来协调,而 “线程” 正是这个机制的核心 —— 是 CPU 调度的最小单位。

从进程到线程:调度单位的进化

我们知道进程是程序运行时的资源载体(比如内存、文件句柄等),但直接调度进程效率较低。想象一下:如果每个程序以进程为单位轮流占用 CPU,每次切换都要重新加载整个进程的资源,会浪费大量时间。于是,操作系统引入了更轻量的 “线程”——线程是进程内部的一个执行单元,是 CPU 真正调度和分配时间的基本单位。早期 Linux 系统曾把线程 “伪装” 成进程来实现(通过共享内存的轻量级进程),后来才发展出独立的线程 API(如 pthread)。这种设计让线程既有进程的独立性(每个线程有独立的执行流),又具备轻量化的优势,成为现代操作系统实现高并发的核心机制。

线程的特性:轻量、共享、依赖
  1. 依附于进程:线程不能独立存在,必须属于某个进程(父进程)。比如你打开一个浏览器(进程),里面每开一个标签页就是一个线程,这些线程共享浏览器进程的内存、网络连接等资源。
  2. 资源极简:线程自身只携带运行必需的 “最小装备”—— 程序计数器(记录下一条指令位置)、一组寄存器(存储临时数据)和栈(保存函数调用栈),几乎不占用额外系统资源。
  3. 共享进程资源:同一进程内的所有线程可以直接访问进程的内存空间、打开的文件、网络连接等,就像同一车间的多个工人共享同一套工具和材料,协作完成任务。
为什么需要线程?

首先是CPU 调度更灵活,比如多个线程可以分时复用同一个 CPU 核心,通过快速切换(如每 10 毫秒切换一次),让用户感觉多个任务在同时进行(如边听歌边打字)。其次是降低资源开销:创建线程比创建进程快得多(无需重新分配整套内存资源),切换线程的成本也更低,适合需要大量并发的场景(如浏览器、服务器程序)。

Java 中,线程无处不在

Java 中不管任何程序都必须启动一个 main 函数的主线程; Java Web 开发里 面的定时任务、定时 器、JSP 和 Servlet、异步消息处理机制,远程访问接口 RM 等, 任何一个监听事件,onclick 的触发事件等 都离不开线程和并发的知识。

CPU核心和线程数之间的关系

物理核心:CPU 的「真实算力单元」

CPU 的「核心数」指物理上的处理单元数量,比如 8 核 CPU 就像有 8 个独立的「工人」,每个工人能同时运行一个线程(任务)。在没有超线程技术时,一个核心同一时间只能执行一个线程,此时核心数等于最大同时运行的线程数(1:1 关系)。
例如:4 核 CPU 最多同时跑 4 个线程,多任务时靠快速切换(如每 10ms 换一次)让用户感觉「同时运行」,但本质上每个核心同一时刻只处理一个线程。

超线程技术:让每个核心「分身」成两个「逻辑处理器」

Intel 的超线程技术(Hyper-Threading)打破了 1:1 的限制。它让每个物理核心模拟出两个「逻辑处理器」,使单个核心能同时处理两个线程的上下文(如寄存器状态、指令队列等)。

  • 原理:物理核心的运算单元(如算术逻辑单元)被两个线程共享,但通过高速切换线程的执行状态,让操作系统以为每个核心有两个独立的处理单元。
  • 效果:核心数与线程数形成 1:2 关系。例如 6 核 CPU 通过超线程变成 12 个逻辑处理器(Windows 任务管理器中显示的「逻辑处理器数」即线程数)。
  • 注意:超线程提升的是线程并发效率(尤其当线程存在等待 IO 等空闲时),但单个核心的真实算力未翻倍(因共享底层运算资源),实际性能提升约 30%-50%。

Java 如何获取核心数?看「逻辑处理器」而非物理核心

Runtime.getRuntime().availableProcessors()

在 Java 中,Runtime.getRuntime().availableProcessors() 返回的是 逻辑处理器数(包含超线程模拟的核心)。比如,6核12线程的CPU返回的是12,4 核无超线程的 CPU就返回 4。

这个值在并发编程中至关重要,因为线程池大小常以此为参考(如 new FixedThreadPool(n)),避免线程数超过 CPU 处理能力导致频繁上下文切换。其次计算密集型任务建议线程数接近逻辑处理器数,IO 密集型可适当增加(因线程等待 IO 时 CPU 可处理其他线程)。

上下文切换(Context switch)

在操作系统里,需要在多个进程或者线程间进行调度。每个线程在使用 CPU 时,都会用到 CPU 里的资源,像 CPU 寄存器和程序计数器。为了保证线程在调度前后能够正常执行,操作系统引入了上下文切换的概念。上下文切换指的是 CPU 从一个进程或线程切换到另一个进程或线程的过程

上下文(Context)的定义

这里的上下文,其实就是 CPU 寄存器和程序计数器在任意时间点的内容。寄存器是 CPU 内部的一小部分高速内存,和 CPU 内部的缓存以及 CPU 外部较慢的 RAM 主内存相比,它的速度非常快。借助寄存器能够快速访问常用值,从而加快计算机程序的执行。程序计数器是一种特殊的寄存器,它的作用是指示 CPU 在指令序列里的位置,会保存正在执行的指令地址或者下一条要执行的指令地址,具体取决于不同的系统。

上下文切换的详细过程

  1. 暂停并保存:暂停一个进程的处理工作,把该进程的 CPU 状态(也就是上下文)存到内存的某个位置。
  2. 获取并恢复:从内存中取出下一个进程的上下文,然后在 CPU 的寄存器中恢复这些内容。
  3. 恢复执行:回到程序计数器所指示的位置,也就是回到进程被中断的代码行,让进程继续执行。

从数据层面来说,站在程序员的角度,上下文切换涉及方法调用过程中的各种局部变量和资源;从线程的角度来看,涉及的是方法调用栈中存储的各类信息。

引发上下文切换的常见原因有线程或进程的切换、系统调用等。上下文切换通常是计算密集型的操作,因为这一过程涉及一系列数据在各种寄存器、缓存之间的来回拷贝。就 CPU 时间而言,一次上下文切换大概需要 5000 - 20000 个时钟周期,而一个简单指令的执行时钟周期只有几个到十几个,由此可见上下文切换的成本是非常高的。

并行和并发

并发(Concurrent):单位时间内的「任务魔术」

核心:交替执行,制造「同时进行」的错觉

单 CPU 核心运行多个线程时,CPU 通过极快的速度(纳秒级)在任务间切换(如线程 A 执行 10 毫秒,切到线程 B 执行 10 毫秒,循环往复)。

本质上同一时刻只有一个任务真正占用 CPU,但切换速度快到人脑无法察觉,看起来像「同时进行」。我们在讲并发的时候必须带上「单位时间」—— 比如 “每秒并发处理 1000 个请求”,离开时间谈并发毫无意义。

举个例子:单核心手机一边播放音乐一边刷微信,实际是 CPU 在两个 App 的线程间高频切换,而非真正同时运行。通俗点讲可以是你是一个单独个体,然后你在地铁上看书,那么相当于你“同时”在做两件事,一件是乘坐地铁,另一件是看书,是一个单独个体在“同一时间”做不止一件事。

并行(Parallel):货真价实的「同时开工」

核心:多个任务在物理层面同步执行

需要多个独立的执行单元(如多核 CPU 的不同核心、多 CPU 服务器、或分布式系统的多台机器)。

举个例子:在同一时间下,多核 CPU 中,核心 1 运行视频渲染,核心 2 同时运行文件压缩,两者互不干扰;通俗点讲,你和开发团队在一起忙活同一个项目,你在苦逼的CV后端代码,我在当前端切图仔,他在和客户沟通新的需求,多个个体同步处理多件事,属于真正的并行。

一句话总结:

并发是 “时间换空间”:用快速切换让单 CPU “假装” 同时处理多任务,适合 IO 密集型场景(如服务器处理大量请求);

并行是 “空间换时间”:靠多个物理核心 / 设备真正同步干活,适合计算密集型场景(如视频渲染、科学计算)。

总结

进程与线程是操作系统资源分配与任务调度的基础,结合 CPU 硬件特性(核心数、超线程)与软件机制(上下文切换、并发并行策略),共同实现高效的多任务处理。理解两者的关系及调度原理,对优化程序性能(尤其是 Java 并发编程)具有关键意义。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值