1.进程、线程基础知识

1.1 进程

进程是什么

运行中的程序

中断是什么

CPU可以从进程1切换到进程2,记录进程1当前状态,要恢复执行进程1就需要向CPU发送中断

并行和并发的区别

并行:同一时刻,进行多个任务。
并发:同一时间段,进行多个任务,切换频率很高让人无法感受到中断。

1.1.1 进程的状态

一个进程的活动期间至少具备三种基本状态,

运行状态(Running),该时刻进程占用CPU
就绪状态(Ready),可运行,由于其他进程处于运行状态而暂时停止运行
阻塞状态(Blocked),该进程正在等待某一事件完成(比如IO操作)而暂时停止运行,这时即使给它CPU控制权也无法运行。

进程的另外两个基本状态:

创建状态(new),进程正在被创建时的状态
结束状态(Exit),进程正在从系统中消失时的状态

完整的进程状态变迁:

挂起状态 为什么产生、是什么意思、有什么作用

如果有大量处于阻塞状态的进程,这些进程会占用物理内存空间,极大的浪费了物理内存。
所以,在虚拟内存管理的操作系统中,通常把阻塞状态的进程的物理内存空间换出到硬盘,再次运行的时候,再从硬盘换入到物理内存。
挂起状态:描述进程没有占用实际的物理内存空间的情况

挂起状态分为两种:

阻塞挂起状态:进程在外存并等待某个事件的出现
就绪挂起状态:进程在外存,但只要进入内存,就立刻运行

还有两种情况也会导致进程挂起:

通过sleep让进程间歇性挂起,原理是设置一个定时器,到期后唤醒进程。
用户希望挂起一个程序的执行,例如Linux中用Ctrl+z挂起进程

1.1.2 进程的控制结构

OS使用进程控制块(process control block,PCB)数据结构来描述进程。
PCB是进程存在的唯一标识

PCB包含什么?

进程描述信息
进程控制和管理信息
资源分配清单
CPU相关信息

每个PCB是如何组织的

通常通过链表的方式进行组织,把具有相同状态的进程链在一起,组成各种队列

1.1.3 进程的控制

进程的创建、终止、阻塞、唤醒的过程

创建进程
终止进程
阻塞进程
唤醒进程

1.1.4 进程的上下文切换

一个进程切换到另一个进程运行,称为进程的上下文切换。

CPU上下文切换

CPU在运行任何任务前,必须依赖CPU寄存器和程序计数器。CPU寄存器和程序计数器就叫做CPU上下文
CPU上下文切换:先把当前任务的CPU上下文保存起来,然后加载新任务的上下文,再跳转到程序计数器所指的新位置,运行新任务。系统内核会存储保持下来的上下文信息,当此任务再次被分配给CPU运行时,CPU会重新加载这些上下文,这样就能保证任务原来的状态不受影响,让任务看起来还是连续运行。
CPU上下文按任务的种类,可以分成:进程上下文切换、线程上下文切换和中断上下文切换。

进程上下文切换 切换什么?

进程的上下文切换不仅包含了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的资源。

发生进程上下文切换的场景有哪些?

1.2 线程

1.3 调度

调度算法

先到先服务:最先进入最先执行,直到完成或被阻塞

短作业优先:运行时间最短最先执行,直到完成或被阻塞

时间片轮转:每个进程享有一个时间片,片完即调度

优先级:高优先级先执行,直到完成或阻塞

多级反馈队列:兼顾优先级和短作业

1.4 进程与线程

什么是进程和线程?

进程(Process) 是指计算机中正在运行的一个程序实例。
线程(Thread) 也被称为轻量级进程,更加轻量。

进程和线程的区别是什么?

线程是进程划分成的更小的运行单位,一个进程在其执行的过程中可以产生多个线程。
线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响。
线程执行开销小,但不利于资源的管理和保护;而进程正相反。

有了进程为什么还需要线程?

进程切换是一个开销很大的操作,线程切换的成本较低。
线程更轻量,一个进程可以创建多个线程。
多个线程可以并发处理不同的任务,更有效地利用了多处理器和多核计算机。而进程只能在一个时间干一件事,如果在执行过程中遇到阻塞问题比如 IO 阻塞就会挂起直到结果返回。
同一进程内的线程共享内存和文件,因此它们之间相互通信无须调用内核。

2.进程间有哪些通信方式

2.1 管道

管道:本机两个亲缘进程通信,存在形式为内存文件

有名管道:本机任意两个进程通信,通信数据遵循先进先出,存在形式为磁盘文件

2.2 消息队列

消息队列:实现消息随机查询,通信数据遵循先进先出,存在于内核,只能显式删除

2.3 共享内存

共享内存:多个进程访问同一个内存区域,依靠互斥锁,信号量等同步操作实现

2.4 信号量

信号量:计数器,实现进程同步

2.5 信号

2.6 Socket

套接字:不同主机之间的进程进行双向通信的端点,用于客户端和服务端之间通过网络进行通信

2.7 总结

3.多线程冲突了怎么办

3.1 为什么要用多线程

总体上来说。
从计算机底层来说: 线程可以比作是轻量级的进程,是程序执行的最小单位,线程间的切换和调度的成本远远小于进程。另外,多核 CPU 时代意味着多个线程可以同时运行,这减少了线程上下文切换的开销。
从当代互联网发展趋势来说: 现在的系统动不动就要求百万级甚至千万级的并发量,而多线程并发编程正是开发高并发系统的基础,利用好多线程机制可以大大提高系统整体的并发能力以及性能。

计算机底层:
单核时代:在单核时代多线程主要是为了提高单进程利用 CPU 和 IO 系统的效率。 假设只运行了一个 Java 进程的情况,当我们请求 IO 的时候,如果 Java 进程中只有一个线程,此线程被 IO 阻塞则整个进程被阻塞。CPU 和 IO 设备只有一个在运行,那么可以简单地说系统整体效率只有 50%。当使用多线程的时候,一个线程被 IO 阻塞,其他线程还可以继续使用 CPU。从而提高了 Java 进程利用系统资源的整体效率。
**多核时代: 多核时代多线程主要是为了提高进程利用多核 CPU 的能力。**举个例子:假如我们要计算一个复杂的任务,我们只用一个线程的话,不论系统有几个 CPU 核心,都只会有一个 CPU 核心被利用到。而创建多个线程,这些线程可以被映射到底层多个 CPU 上执行,在任务中的多个线程没有资源竞争的情况下,任务执行的效率会有显著性的提高,约等于(单核时执行时间/CPU 核心数)。

3.2 竞争与协作

3.3 互斥与同步的实现和使用

3.4 经典同步问题

4.怎么避免死锁

4.1 死锁的概念

什么是:多个进程/线程同时被阻塞,一个/全部在等待某个资源被释放,由于进程/线程被无限期阻塞导致程序无法被正常终止。

4.2 模拟死锁问题的产生

产生死锁的4个必要条件,缺一不可:

1资源互斥,一次只能被一个进程占有
2占有并等待,进程占有A资源并等待B资源释放
3非抢占,资源不可被抢占,只有任务完成才会释放
4循环等待,进程A等进程B释放,进程B等进程C释放,进程C等进程A释放

4.3 解决死锁的思路与方法

思路

可以从预防、避免、检测、解除四个方面考虑

详细的四种思路:

方法:

4.4 利用工具排查死锁问题

4.5总结

5.什么是悲观锁、乐观锁

5.1 互斥锁与自旋锁

5.2 读写锁

5.3 乐观锁与悲观锁

5.4 总结

6.一个进程最多可以创建多少个线程

7.线程崩溃了,进程也会崩溃吗

7.1 线程崩溃,进程一定会崩溃吗

7.2 进程是如何崩溃的——信号机制

7.3 为什么线程崩溃不会导致JVM进程崩溃

7.4 openJDK 源码解析