概念

**
为了便于理解,引用网上的一个例子:

计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运行。

假定工厂的电力有限,一次只能供给一个车间使用。也就是说,一个车间开工的时候,其他车间都必须停工。

背后的含义就是,单个CPU一次只能运行一个任务

CPU = 工厂
**

进程


进程就类似于上述例子的车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。

进程 = 车间

进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能

打开任务管理器,左上角赫然显示进程二字,证明我们正在运行的程序(如TIM、Word)都是进程
image.png

线程

**
一个车间里,可以有很多工人。他们协同完成一个任务,线程就好比车间里的工人,就像一个车间可以同时分派多个工人,一个进程可以包括多个线程。

线程 = 工人

某些进程内部还需要同时执行多个子任务。例如,我们在使用Word时,Word可以让我们一边打字,一边进行拼写检查,同时还可以在后台进行打印,我们把子任务称为线程。

线程是进程的一个实体是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是
它可与同属一个进程的其他的线程共享进程所拥有的全部资源
image.png

多线程

就像一个车间可以同时分派多个工人,一个进程可以包括多个线程。

多线程指在单个进程中可以同时运行多个不同的线程执行不同的任务。
image.png

进程与线程的区别**

开销方面每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。

所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)

内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源。

包含关系一个进程可以包含多个子线程,一个线程只能属于一个进程
**

多线程与多进程


多进程表示一个工厂可以有多个车间同时运作,多线程表示一个车间里面可以有多个工人同时工作。

同一个应用程序,既可以有多个进程,也可以有多个线程,因此,实现多任务的方法,有以下几种:
1、多进程模式(一个应用程序有多个进程,每个进程只有一个线程)
image.png
2、多线程模式(一个应用程序只有一个进程,进程有多个线程)
image.png
3、多进程+多线程模式(多个进程,每个进程有多个线程,复杂度最高)
image.png

而很明显,我们的操作系统采用的是最后一种方式:
(1)以多进程形式,允许多个任务同时运行【同时开了TIM和Word,甚至于是IDEA】
(2)以多线程形式,允许单个任务分成不同的部分运行;【很明显我们可以在Word中同时打字和校验】
(3)提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源。【Word打开某个文件的时候,IDEA里的程序没办法删除对应文件】

CPU和进程与线程的关系

进程是操作系统进行资源(包括**CPU**、内存、磁盘IO等)分配的最小单位

线程是CPU调度和分配的基本单位

有句话说CPU只能看到线程。操作系统将一个进程丢给CPU,而CPU能见到的就只是这个进程里面的线程,所以调度也只能调度分配这些线程(分配到运算核心)。

CPU

计算机有5大基本组成部分,运算器(计算机的运算系统),控制器(计算机的控制系统),存储器(计算机存储系统:内存+外存),输入设备(鼠标、键盘),输出设备(显示器、打印机等)。

运算器和控制器封装到一起,加上寄存器组和cpu内部总线构成中央处理器(CPU)CPU的根本任务,就是执行指令
**
进程?线程?多线程? - 图7

CPU分为单核CPU和多核CPU

一、单核CPU—同一时间仅能运行一个线程

单核就是一个芯片里面只有一个CPU运算核心,处理多个线程时,只能分时处理。

单核CPU上运行的多线程程序, 同一时间只能一个线程在跑, 系统帮你切换线程 系统给每个线程分配时间片来执行, 每个时间片大概10ms左右, 看起来像是同时跑, 但实际上是每个线程跑一点点就换到其它线程继续跑。 线程没有自己的独立

CPU当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再次加载这个任务的状态,从任务保存到再加载的过程就是一次上下文切换

image.png

感觉上我们的大脑就像一个单核CPU,无法真正同时做两件事情。像我们在读一本英文的技术书籍时,发现某个单词不认识, 于是便打开中英文词典,但是在放下英文书籍之前,大脑必须先记住这本书读到了多少页的第多少行,等查完单词之后,能够继续读这本书。这样的切换是会影响读书效率的,同样上下文切换也会影响多线程的执行速度。

现在推出的CPU基本没有单核CPU了。

二、多核CPU—多个核心同一时间运行多个线程

在**一颗芯片里集成了多个CPU运算核心相当于多个单核CPU同时工作**。因此,多核处理器可以同时处理多个线程,而不用等上一个线程完成。比如CPU是4核的话,把线程ABCD分配到核心1234,其他的线程依然要等待分配

线程切换的过程

  1. 挂起当前任务(线程),将这个任务在 CPU 中的状态(上下文)存储于内存中的某处

  2. 恢复一个任务(线程),在内存中检索下一个任务的上下文并将其在 CPU 的寄存器中恢复

  3. 跳转到程序计数器所指向的位置(即跳转到任务被中断时的代码行),以恢复该进程在程序中

程序计数器是一个专用的寄存器,用于表明指令序列中 CPU 正在执行的位置,存的值为正在执行的指令的位置或者下一个将要被执行的指令的位置。

JAVA程序和进程与线程的关系


程序:一段静态的代码,一组指令的有序集合,它本身没有任何运行的含义,它只是一个静态的实体,是应用软件执行的蓝本。

进程:是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个动态的实体,它有自己的生命周期。它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而被撤消。反映了一个程序在

线程: 可以理解为进程的多条执行线索,每条线索又对应着各自独立的生命周期

一个java程序运行起来,只会有一个进程,但是可以有多个线程

为什么需要多线程?


用炒菜来举例

1、提升性能
**
单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。(我炒菜的时候只能炒菜,不能拿碗也不能准备下一道菜的食材,炒完了这道菜能去准备下一道菜的食材,耗时起码20分钟)

多线程处理可以同时(或类似同时)运行多个线程(炒菜的时候可以先去准备下一道菜的食材,耗时大概15分钟,甚至是10分钟,因为我可以开两口锅)

2、避免阻塞(异步调用)
在Java的世界中默认是单线程的,上一步操作没有完成的时候,下一步操作绝不可能执行(同步),这种时候如果上一步和下一步操作并没有什么关联性,当上一步操作涉及到非常多的RPC、数据库访问、磁盘IO等操作,这种情况很有可能出现阻塞,下一步操作无法执行。(炒上一道菜缺了份耗油,但是下一道菜完全不用,死耗在那里谁也别想吃)
而多线程则可以避免这个问题(我可以开两口锅)

3、提高CPU利用率(降低CPU空转率)**
假如CPU是单线程的,我们在浏览器点击链接访问一个网页,如果网页返回的很慢,CPU会存在大量的闲置时间,而这段时间我们啥也不能做,不能动鼠标也不可以做别的事,只能等待页面响应(最后返回访问失败是个人都得炸)

开发中什么场景需要用到多线程?

1、后台任务,例如:定时向大量(100w以上)的用户发送邮件;
2、异步处理,例如:发微博、记录日志等;
3、大任务循环:如导入数据,当数据非常大的时候,可以开多个线程分块导入,加快速度

总之使用多线程就是为了充分利用cpu的资源,提高程序执行效率,当发现一个业务逻辑执行效率特别低,耗时特别长,就可以考虑使用多线程。