进程
什么是进程?
跑起来的程序都是进程,后缀为
.exe
文件都是可执行文件,这些可执行文件都是文件,都是静静地躺在硬盘上的,在你双击之前这些文件对你的计算机没有任何的影响,但是一旦你双击了之,操作系统就会把这些文件加载到内存中,并且让CPU开始执行exe内部的一些指令(里面存了很多这个程序对应的二进制指令)
把这些运行起来的可执行文件称为"进程"
咱们写的代码,最终的目的都是要跑起来,都是要成为一些进程,对于Java代码来说,最终都是通过Java进程跑起来的(次数所说的Java进程就是我们平时所说的jvm)
进程(process)还有另一个名字(task)
操作系统是如何管理进程的?
- 先描述一个进程(明确出一个进程上面的相关属性)此处的描述就是用C语言中的"结构体"(也就和Java中的类差不多)操作系统中描述进程的这个结构体称为"PCB"
- 再组织若干个进程(使用一些数据结构,把很多描述进程的信息给放到一起,方便进行增删改查)典型的实现就是用双向链表把进程的每个PCB给串起来
PCB中的一些属性
- pid(进程ID)进程的身份标识(进程的身份证号)
- 内存指针 指明了这个进程要执行的代码/指令在内存的哪里,以及这个进程执行中依赖的数据在哪里,当运行一个exe文件的时候,此时操作系统就会把这个exe文件加载到内存当中,变成进程
- 文件描述符表 程序执行过程中经常和文件打交道(文件是在硬盘上的)进程每次打开一个文件,就会在文件描述符表上多增加一项… 这个文件描述符表就可以视为一个数组,里面的每个元素又是一个结构体,就对应一个文件的相关信息)
这个文件描述符表的下标,就称为文件描述符
上面的属性都是一些基础的属性,下面的一组属性主要是为了实现进程调度
什么是进程调度?
这个是理解进程管理的重要的话题,现在的操作系统都是"多任务操作系统",像我们现在的Windows操作系统,就是多任务的,同一时刻很多进程都在运行
并行和并发
并行:微观上,两个CPU的核心同时执行两个任务的代码
并发:微观上,一个CPU核心,先执行一会任务1,再执行一会任务2再执行一会任务3…再执行一会任务1 只要切换的足够快,宏观上看起来,就好像那么多任务在同时执行一样
并发和并行这两件事,只是在微观上是有区分的宏观上咱们区分不了,微观上的这里的区分都是操作系统自动调度的结果正因为在宏观上区分不了并行和并发,我们在写代码的时候也就不去具体区分这两个词实际上通常使用"并发"这个词,来代指"并行+并发"
- 优先级 先给谁分配时间,后给谁分配时间,分别都排队等了好久给线程调度提供依据
- 记账信息 统计了每个进程,都分别执行了多久,分别执行了哪些指令分别都排队等了多久,给进程调度提供依据的
- 上下文 就表示上次进程被调度处CPU的时候,当时程序的状态,下次进程上CPU的时候,就可以回复之前的状态,然后继续执行下去. 进程被调度出CPU之前,要先把CPU中的所有的寄存器中的数据都给保存到内存中(PCB的上下文字段中)相当于存档了,下次进程被调度上CPU的时候就可以从刚才的内存中恢复这些数据到寄存器当中,相当于读档了 存档存储的信息,就称为"上下文"
进程的调度
进程的调度,其实就是操作系统在考虑CPU资源如何给各个进程分配
由于操作系统上同时运行着很多的进程,如果某个进程出现了bug,进程崩溃了,是否会影响到其他的进程那?
现在的操作系统能够做到这一点,就是"进程的独立性"来保证的,就依仗了"虚拟空间地址"
进程之间通过虚拟空间地址已经隔离开了,但是在实际工作当中,进程之间有的时候还是需要交互的
类似的,咱们的两个进程之间也是隔离开的,也是不能交互的,操作系统也是提供了类似的"公共空间",进程A就可以把数据先放到公共空间,进程B再取走
进程间的通信
操作系统中提供的"公共空间"有很多种,并且各有特点,有的存储空间大,有的小,有的速度快,有的慢,操作系统中提供了多种这样的进程间的通信机制(有些机制属于历史遗留,已经不适合我们现在的程序开发)
最主要的进程间的通信方式,两种:
文件操作
网络操作(socket)
以上知识的总结:
- 进程是啥?跑起来的程序
- 进程是怎么管理的? 描述+组织
- 进程的PCB里有啥?
- 进程的调度是怎么进行的? 时间管理大师
- 进程的独立性是怎么回事?
- 进程之间如何通信?
线程
线程是啥?
为啥要有线程?
因为我们系统支持多任务了,程序员也就需要"并发编程",通过多进程完全可以实现并发编程
但是有个小问题, 如果需要频繁的创建/销毁进程,这个事情成本是比较高的,如果需要频繁的调度进程,这个事情成本是比较高的
创建进程就要分配资源1)内存2)文件销毁进程也得释放资源1)文件2)内存
如何解决这个问题?
思路有两个
- 进程池(数据库进程池,字符串常量池)进程池虽然能解决上述问题,提高效率,同时也有问题,池子里的闲置进程,不使用的时候也在消耗资源,消耗的资源太多了
- 使用线程来实现并发编程, 线程比进程更轻量,每个进程可以执行一个任务,每个线程也能执行一个任务(执行一段代码)也能够实现并发编程,创建线程的成本比创建进程要低很多,销毁线程的成本也比销毁进程低很多,调度线程的成本也比调度线程低很多
为啥线程比进程更轻量?
进程重量是重在哪里?重在资源申请释放(在仓库里找东西),线程是包含在进程中的,一个进程的多个线程,共用同一份资源(同一份内存+文件),只是创建进程的第一个线程的时候(由于要分配资源),成本是相对高的,后续这个进程中再创建其他线程,这个时候成本就更低一些,不必在分配资源了
经典面试题:谈谈进程和线程的区别和联系?
- 进程包含线程,一个进程里可以有一个线程也可以有多个线程
- 进程和线程都是为了处理并发编程这样的场景,但是进程有问题,频繁创建和释放的时候效率低,相比之下,线程更轻量,创建和释放效率更高(为啥更轻量?少了申请释放资源的过程)
- 操作系统创建进程,要给进程分配资源,进程是操作系统分配资源的基本单位.操作系统创建的线程是要在CPU上调度执行.线程是操作系统调度执行的基本单位(前面的时间管理大师(妹子的事情)当咱们说的是调度的进程,但是更准确的说是调度线程)----前面的例子相当于是每个进程里只有一个线程,可以视为是在调度进程,但是如果进程有多个线程更严谨的说法,还是以线程为单位进行调度
- 进程具有独立性.每个进程有各自的虚拟地址空间,一个进程挂了,不会影响到其它进程.同一个进程的多个线程共用同一个内存空间,一个线程挂了可能影响到其他线程了,甚至导致整个进程崩溃