线程是进程的线程。
进程
程序 是一组计算机能识别和执行的指令,在程序不运行的时候 就是在磁盘存储中的文件。
进程 是操作系统中处于执行状态的 程序 ,每运行一个程序,就创建一个进程。
程序从开始执行到结束,也代表着进程的创建到消亡。称之为进程的生命周期 。
进程的生命周期
进程的生命周期分为5个状态
创建状态:系统已为其分配了PCB,但进程所需资源尚未分配,即创建工作尚未完成。
就绪状态:进程已经获得了除cpu以外的所有其他资源,在就绪队列中的等待cpu的调度。
执行状态:进程已经获得cpu的执行时间片,以及所有需要的资源正在运行。
阻塞状态:进程因休眠或,等待所需的资源而放弃cpu。
终止状态:进程执行完毕或因意外被终结,不能再执行。
操作系统在分配资源时,会以进程为基本单位来分配。在线程没有出现前,进程也是cpu调度和执行的基本单位。
进程因此有独立的代码和数据空间,也因此具有健壮性:一个进程崩溃不会对其他进程产生影响。
为什么要有时间片?为什么要在就绪态和执行态间来回切换,即进程间切换?
在多任务场景中,在有很多进程同时等待处理时,处理器会按顺序一个个处理。为了让用户感觉到这些进程同时在被处理,设置时间片,每一个进程都处理一段时间就切换到下一个进程,处理器在进程间频繁的切换来达到这种效果。
进程的局限和线程的产生
进程间的切换需要做很多工作,消耗很多资源: 为了让cpu知道进程从哪里加载处理,需要操作系统帮进程设置好cpu寄存器和程序计数器(称为上下文),并存储在系统的内核中,并在进程重新调度室再次加载进来。这样就限制了系统中进程的数量不能很多。
为了解决这个限制,后来提出将进程的资源分配和cpu调度的属性分开,进程仍作为资源分配的基本单位,在进程中设置更小的cpu调度单位,他们共享进程的资源。 这种更小的单位便是线程。
线程
因此有了文章最开始的那句话“线程是进程的线程”。
线程成为了cpu调度的基本单位,一个进程中的线程共享进程的资源,但各自拥有独立的方法栈和程序计数器。如图所示:
本地方法栈和虚拟机栈
此处参考ThinkWon博主的文章。
虚拟机栈:每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
本地方法栈:和虚拟机栈所发挥的作用非常相似,区别是: 虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。 在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一。
为了保证线程中的局部变量不被别的线程访问到,虚拟机栈和本地方法栈是线程独立的。
程序计数器:
1 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
2 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。
程序计数器独立主要是为了线程切换后能恢复到正确的执行位置。
总结进程和线程的特性
1 线程是进程的线程。
2 进程是操作系统分配资源的基本单位,线程是cpu调度和执行的基本单位。
3 进程有独立的代码和数据空间,也因此具有健壮性:一个进程崩溃不会对其他进程产生影响。线程没有独立的数据空间,一个线程崩溃整个进程都死掉。