进程和线程
进程
进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建、运行到消亡的过程。
在Java中,当我们启动main函数其实就是启动了一个JVM进程,而main函数所在的线程其实就是这个进程中的一个线程,也称主线程。
在 Windows 中通过查看任务管理器的方式,我们就可以清楚看到 Windows 当前运行的进程(.exe 文件的运行)。
线程
线程与进程相似,但线程是一个比进程更小的执行单位,一个进程在其执行过程中可以产生多个线程。
各进程之间基本上是相互独立的,与进程不同的是同类线程共享进程的堆和方法区资源,但每个线程都有自己的程序计数器、Java虚拟机栈和本地方法栈。
系统产生一个线程或是在多个线程之间切换工作时,负担要比进程小得多,因此线程也被称作轻量级进程。
Java 程序天生就是多线程程序,一个 Java 程序的运行是 main 线程和多个其他线程同时运行。
进程和线程的区别
根本区别: 进程是操作系统资源分配的基本单位,而线程是处理器(CPU)任务调度和执行的基本单位。
资源开销: 每个进程都有自己独立的代码和数据空间(程序上下文),进程之间的切换开销比较大;线程可以看作轻量级进程,同类的线程共享进程的堆和方法区(JDK1.7及之前实现为永久代,JDK1.8及之后实现为元空间)资源,但是每个线程都有自己的程序计数器、Java虚拟机栈和本地方法栈,线程之间的切换开销比较小。
包含关系: 如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
内存分配: 同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的。
影响关系: 一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉,所以多进程要比多线程健壮。
执行过程: 每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行。
总结: 线程是进程划分成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响。线程执行开销小,但不利于资源的管理和保护;而进程正相反。
程序计数器为什么是线程私有的?
程序计数器主要有以下两个作用:
- 程序计数器可以看作当前线程所执行字节码的行号指示器,字节码解释器通过改变程序计数器的值来依次读取指令,从而实现对代码的流程控制,如顺序执行、选择、循环和异常处理等。
- 在多线程场景下,程序计数器还用来记录当前线程执行的位置,从而当线程切换回来时能知道线程上一次运行到哪里了。
需要注意的是,如果执行的是 native 方法,那么程序计数器记录的是 undefined 地址,只有执行的是 Java 代码时程序计数器记录的才是下一条指令的地址。
所以,程序计数器线程私有主要是为了记录每个线程切换之前执行的位置以便线程切换后能恢复到正确的执行位置。
Java虚拟机栈和本地方法栈为什么是线程私有的?
- Java虚拟机栈: Java虚拟机栈是线程私有的,每个方法执行的时候都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接和方法返回地址等信息。
- 本地方法栈: 本地方法栈的作用和虚拟机栈的作用非常相似,他们之间区别是Java虚拟机栈是为虚拟机执行Java方法(也就是字节码)服务的,而本地方法栈则是为虚拟机执行本地(Native)方法服务的。本地方法执行的时候,也会在本地方法栈中创建一个栈帧用于存储本地方法的局部变量表、操作数栈、动态链接和方法返回地址等信息。
所以,从上面的介绍可以看出,Java虚拟机栈和本地方法栈线程私有主要是为了保证每个线程中的局部变量不被其他线程访问到。
并行与并发
并行
并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行,所以无论从微观还是从宏观来看,二者都是一起执行的。
并发
并发(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。
并行与并发的区别
-
并行只能在多处理器系统中存在,而并发可以在单处理器和多处理器系统中都存在。
-
并行要求程序能够同时执行多个操作,而并发只是要求程序“看着像是”同时执行多个操作,其实是交替执行。
总结
并发针对单核 CPU 而言,它指的是 CPU 交替执行不同任务的能力;并行针对多核 CPU 而言,它指的是多个核心同时执行多个任务的能力。
单核 CPU 只能并发,无法并行;换句话说,并行只可能发生在多核 CPU 中。在多核 CPU 中,并发和并行一般都会同时存在,它们都是提高 CPU 处理任务能力的重要手段。
同步和异步
同步
同步,调用方调用某个东西,需要等待这个调用返回结果才能继续执行后续任务。
异步
异步,和同步相反,调用方调用某个东西,不用等待这个调用返回结果,就可以直接执行后续任务。