进程

操作系统进行资源分配和调度的基本单位,每一个进程都是一个应用程序的执行实例,比如我们启动的一个java项目就是一个jvm进程,操作系统为jvm分配运行内存等资源,进程中包含一个或多个线程,线程之间共享进程的资源(比如堆、栈、方法区等)。

线程

CPU运行的最小单位,线程之间共享进程的资源,也有自己的私有空间,比如虚拟机栈、本地方法栈、程序计数器。

进程上下文切换

线程上下文切换

CPU通过分配时间片来执行任务,当一个任务的时间片用完,就会切换到另一个任务。在切换之前会保存上一个任务的状态,当下次再切换到该任务,就会加载这个状态,任务从保存到再加载的过程就是一次上下文切换。

  • 切出:一个线程被剥夺处理器的使用权而被暂停运行
  • 切入:一个线程被系统选中占用处理器开始或继续运行

线程的上下文是什么?
对于CPU来说一个线程就是多条指令集合,线程的运行实质上是多条指令在CPU上的运行,而上下文是指线程私有空间的内容。比如虚拟机栈、本地方法栈保存了某一时刻线程局部变量的值,程序计数器保存了线程此刻执行到哪一条指令的位置。

导致上下文切换的原因?

  • CPU分配的时间片用完了
  • 有个优先级更高的线程需要被执行
  • 手动操作比如java线程的sleep、yield、wait、join、synchronized、lock等
  • 读取数据库操作由于数据量较大引起IO阻塞,线程会被挂起直到读取完毕再次回归等待被CPU调度

上下文切换的过程?
放发生切换的时候,CPU会把被挂起线程的上下文保存在程序计数器和寄存器中,程序计数器存储正在执行的指令序列的位置、寄存器存储工作变量,然后从高速缓存中清除掉被挂起线程的上下文,去加载新线程的上下文到高速缓存中。因此线程上下文的切换需要消耗CPU的资源。

并发与并行

单CPU操作系统中多个线程同时运行,实质上是交替占有CPU使用权的过程,同时运行只是CPU处理过快造成的错觉,这种现象可以称作为线程并发运行

到了多CPU时代才实现真正意义上的多线程同时运行,比如4颗CPU的操作系统可以做到4个线程的同时运行,但是操作系统中可能有很多线程需要被执行,比如有16个线程在运行,那么平均4个线程仍然要争夺一个CPU的使用权,只是同一时刻必然有4个争夺到使用权,这种现象称作为线程并行运行

由此可以看出,操作系统中CPU的数量对多线程编程非常重要。因此项目开发中要尽量参考所在服务器的CPU配置,作出适当的线程池参数以避免频繁的上下文切换带来的性能损耗。同样在选取机器配置上尽量考虑放置服务的线程特点,比如存放redis服务选用多处理器的CPU没有任何意义,redis永远只在一个处理器上面运行。

线程安全

在开发中使用过线程都知道,多线程编程需要面对线程安全问题,而线程安全问题归根结底就三个方面:可见性、原子性、有序性,下一章节会详细讲解这些问题。

评论