操作系统如何实现多线程
首先还是看多线程多进程在硬件上意味着什么,对于多CPU情况,多线程是如何进行调解的。复习下基本的概念
进程:是操作系统(OS)[windows,Linux,Mac]进行资源(CPU、内存、磁盘、IO、带宽等)分配的最小单位——>QQ,微信,网易云等;
线程:是CPU调度和分配的基本单位。一个进程可由多个线程的执行单元组成,每个线程都运行在同一进程的上下文中,共享同样的代码和全局数据。对于java来说,一个jvm进程至少有一个线程,也就是main方法所在的线程,我们把它叫做主线程,通过主线程可以创建更多线程。此外,线程又分为用户线程和守护线程。两者区别在于,守护线程会随着主线程结束而结束。
进程=容器,包含了该进程的所有线程。线程共享进程拥有的资源,例如00000000ff~00000ff之间的逻辑内存地址。
进程是程序的一次执行过程,是对CPU的抽象,是正在运行的程序的抽象。操作系统通过调度将CPU的控制权交给某个进程。
进程控制块(PCB)是操作系统用于管理控制进程的一个专门的数据结构,记录进程的各种属性
PCB是系统感知进程存在的唯一标志,进程与PCB是一一对应的,PCB包含的信息:
- 进程描述信息:进程标识符PID,唯一,整数,进程名(不唯一),用户标识符userID,进程组关系(兄弟父子关系)
- 进程控制信息:当前状态,优先级,代码执行入口,运行统计信息,进程间同步和通信,进程队列指针,进程消息队列指针
- 所拥有的资源和使用情况:虚拟地址空间的状况,打开文件列表
- CPU现场信息:进程不运行时的寄存器值和指向该进程的页表的指针
进程有以下状态模型:
在硬件架构中还有一个进程队列,用来存放进程。操作系统会给一类进程安装一个或者多个队列。队列元素为PCB,伴随进程状态的改变,其PCB从一个队列进入另一个队列,然后再进行出入的操作。
至于JVM和操作系统的关系是如上图所示的,而操作系统其实也是一个程序,JVM是建立在操作系统之上的程序。
进程是一个程序的单次执行,如果一个程序持续占有CPU,就会从CPU开启到结束持续性的占用CPU。于是出现了操作系统调度器,而进程也成为了调度单位.在这里就出现了并发的概念,调度器切换,CPU给不同进程使用的速度非常快。
线程是进程的衍生,一个进程可以拥有多个线程,可以理解为线程拆分开了进程。例如读线程,写线程。
如果计算机有多个cpu核,且计算机中的总的线程数量小于核数,那线程就可以并行运行在不同的核中,如果是单核多线程,那多线程之间就不是并行,而是并发,即为了均衡负载,cpu调度器会不断的在单核上切换不同的线程执行,但是我们说过,一个核只能运行一个线程,所以并发虽然让我们看起来不同线程之间的任务是并行执行的,但是实际上却由于增加了线程切换的开销使得代价更大了。如果是多核多线程,且线程数量大于核数,其中有些线程就会不断切换,并发执行,但实际上最大的并行数量还是当前这个进程中的核的数量,所以盲目增加线程数不仅不会让你的程序更快,反而会给你的程序增加额外的开销。
实现并行计算有三种方式,多线程,多进程,多进程+多线程。如果是多进程,因为每个进程资源是独立的(地址空间和数据空间),就要在操作系统层面进行通信,如管道,队列,信号等;多线程的话会共享进程中的地址空间和数据空间,一个线程的数据可以直接提供给其他线程使用,但方便的同时会造成变量值的混乱,所以要通过线程锁来限制线程的执行
并行只存在于多个CPU的情况下,单CPU只能做到并发。对于CPU而言, CPU 看到的是线程,看不到进程,进程是 OS 上的概念。
CPU只能做一个事情就是执行command,给什么做什么。
那么有没有可能2个CPU执行一个进程中不同线程呢?逻辑上我觉得是可行的,主存只有一个,CPU只是执行的工具,如果一个进程的不同线程不存在互相依赖的情况那么就肯定可以进行这种情况的执行。
CPU在一个时间点只能做一件事,因为切换的速度快所以看起来好像是同时执行多个线程而已。
实际上就是用定时器来做时基,以时间片的方式分别执行来实现的,只不过实现起来细节比较复杂,核心思想就是你猜想的那样。划分一块内存区域做线程的上下文切换空间,另外以一个定时器做定时时基。例如设为1ms,每隔1ms检测是否有其它线程要工作,如果有,保存当前线程的CPU寄存器以及工作状态到当前线程的上下文空间,从要运行的线程上下文空间取出寄存器值填充到CPU寄存器中,这样就完成了线程的切换,CPU就接着另一个线程的工作继续做下去了。