进程、线程和协程
进程
进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建、运行到消亡的过程。
在Java中,当我们启动main函数其实就是启动了一个JVM进程,而main函数所在的线程其实就是这个进程中的一个线程,也称主线程。
在 Windows 中通过查看任务管理器的方式,我们就可以清楚看到 Windows 当前运行的进程(.exe 文件的运行)。
线程
线程与进程相似,但线程是一个比进程更小的执行单位,一个进程在其执行过程中可以产生多个线程。
各进程之间基本上是相互独立的,与进程不同的是同类线程共享进程的堆和方法区资源,但每个线程都有自己的程序计数器、Java虚拟机栈和本地方法栈。
系统产生一个线程或是在多个线程之间切换工作时,负担要比进程小得多,因此线程也被称作轻量级进程。
Java 程序天生就是多线程程序,一个 Java 程序的运行是 main 线程和多个其他线程同时运行。
进程和线程的区别
根本区别: 进程是操作系统资源分配的基本单位,而线程是处理器(CPU)任务调度和执行的基本单位。
资源开销: 每个进程都有自己独立的代码和数据空间(程序上下文),进程之间的切换开销比较大;线程可以看作轻量级进程,同类的线程共享进程的堆和方法区(JDK1.7及之前实现为永久代,JDK1.8及之后实现为元空间)资源,但是每个线程都有自己的程序计数器、Java虚拟机栈和本地方法栈,线程之间的切换开销比较小。
包含关系: 如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
内存分配: 同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的。
影响关系: 一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉,所以多进程要比多线程健壮。
执行过程: 每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行。
总结: 线程是进程划分成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响。线程执行开销小,但不利于资源的管理和保护;而进程正相反。
协程
协程是一种轻量级的线程,协程的实现方式是在一个线程中,通过切换执行上下文来实现多个任务的并发执行。协程的切换不需要操作系统的介入,因此协程的切换速度非常快,开销也非常小。协程的特点是可以在一个线程中开启多个协程,每个协程之间共享线程的内存空间,因此协程也可以完成复杂的任务,如异步编程、爬虫、游戏等。
协程(Coroutine)是一种轻量级的用户态线程,可以在一个线程中实现多个任务的并发执行。协程的实现方式是通过切换执行上下文(Context)来实现的。在一个线程中,协程有自己的栈空间和执行上下文,可以保存任务的状态和执行位置,以便稍后恢复执行。
协程的实现方式可以分为两种:一种是基于堆栈的实现方式,另一种是基于状态机的实现方式。
基于堆栈的实现方式是利用堆栈来保存协程的状态和执行信息。当协程被挂起时,它的堆栈状态被保存下来,当协程被恢复时,它的堆栈状态被恢复,从而实现了协程的暂停和恢复执行。
基于状态机的实现方式是利用状态机来保存协程的状态和执行信息。当协程被挂起时,它的状态被保存到状态机中,当协程被恢复时,它的状态被从状态机中恢复,从而实现了协程的暂停和恢复执行。
无论是基于堆栈的实现方式还是基于状态机的实现方式,协程都可以在一个线程中实现多个任务的并发执行,提高了应用程序的并发性能。同时,协程也具有轻量级、低开销、高效率等特点,适用于处理I/O密集型和计算密集型任务。
线程与协程的区别
线程和协程都是多任务处理的技术,但是它们之间有很多区别,下面列举几点:
-
调度方式
线程是由操作系统负责调度的,它们是操作系统的一种资源。线程的调度和切换需要操作系统的介入,开销比较大,但是线程的并发性和并行性比较高。
**协程是由程序控制的,它们是用户空间的资源,不依赖于操作系统。**协程的切换和调度由程序控制,因此开销比较小,但是并发性和并行性比较低。 -
内存占用
线程的内存占用比较大,因为每个线程都需要独立的堆栈、寄存器和虚拟内存空间等资源,而协程则共享相同的堆栈和虚拟内存空间,因此协程的内存占用比较小。 -
编程复杂度
线程需要考虑锁、同步、异步等问题,编程复杂度比较高。
协程可以通过 yield、await 等关键字来实现状态的保存和恢复,编程复杂度比较低。 -
执行效率
线程切换和调度需要操作系统的介入,开销比较大,执行效率比较低。
协程切换和调度由程序控制,开销比较小,执行效率比较高。 -
可扩展性不同
线程的可扩展性比较差,因为线程之间的调度和同步需要操作系统的支持,而操作系统的线程调度和同步机制有一定的限制,而协程的可扩展性比较好,因为它在用户程序层面实现了调度和同步,可以根据需要进行灵活的设计。
总的来说,线程适用于 CPU 密集型的任务,协程适用于 I/O 密集型的任务。
线程适用于 CPU 密集型的任务,协程适用于 I/O 密集型的任务
线程和协程的适用场景主要是由于它们在任务调度方面的特点决定的。
对于 CPU 密集型的任务,比如大量的计算、排序等,需要大量的 CPU 资源,线程可以让程序在多个 CPU 核心上并行执行,从而提高执行效率。但是线程的切换和调度需要操作系统的介入,开销比较大,因此线程数量过多时,会降低程序的效率。
对于 I/O 密集型的任务,比如网络请求、文件读写等,需要等待 I/O 操作完成后才能继续执行后续任务,这时线程的执行效率就会受到限制。而协程可以通过 yield、await 等关键字来实现状态的保存和恢复,从而避免了线程切换的开销,提高了程序的效率,因此协程适用于 I/O 密集型的任务。
总之,线程适用于需要大量的 CPU 资源的任务,而协程适用于需要大量的 I/O 操作的任务。在实际应用中,我们需要根据具体的场景选择合适的技术来实现任务的处理。
程序计数器为什么是线程私有的?
程序计数器主要有以下两个作用:
- 程序计数器可以看作当前线程所执行字节码的行号指示器,字节码解释器通过改变程序计数器的值来依次读取指令,从而实现对代码的流程控制,如顺序执行、选择、循环和异常处理等。
- 在多线程场景下,程序计数器还用来记录当前线程执行的位置,从而当线程切换回来时能知道线程上一次运行到哪里了。
需要注意的是,如果执行的是 native 方法,那么程序计数器记录的是 undefined 地址,只有执行的是 Java 代码时程序计数器记录的才是下一条指令的地址。
所以,程序计数器线程私有主要是为了记录每个线程切换之前执行的位置以便线程切换后能恢复到正确的执行位置。
Java虚拟机栈和本地方法栈为什么是线程私有的?
- Java虚拟机栈: Java虚拟机栈是线程私有的,每个方法执行的时候都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接和方法返回地址等信息。
- 本地方法栈: 本地方法栈的作用和虚拟机栈的作用非常相似,他们之间区别是Java虚拟机栈是为虚拟机执行Java方法(也就是字节码)服务的,而本地方法栈则是为虚拟机执行本地(Native)方法服务的。本地方法执行的时候,也会在本地方法栈中创建一个栈帧用于存储本地方法的局部变量表、操作数栈、动态链接和方法返回地址等信息。
所以,从上面的介绍可以看出,Java虚拟机栈和本地方法栈线程私有主要是为了保证每个线程中的局部变量不被其他线程访问到。
详细介绍进程和程序的区别
进程(Process)和程序(Program)是计算机科学中两个重要的概念。虽然它们在某些方面有相似之处,但它们的含义和作用有很大的差别。下面是它们的详细介绍以及区别:
-
程序是指一组指令的集合,它是计算机执行任务的一种描述方式;而进程是指正在执行的程序的实例。换句话说,程序是一个静态的概念,而进程是一个动态的概念。
-
程序只是一个文件,它是计算机存储介质上的一段二进制代码,它只有在被加载到内存中并被操作系统调用执行时才成为进程。进程包含了程序的代码、数据以及运行时的运行环境。在操作系统中,进程是资源分配的基本单位,它包含了代码、数据、内存、文件、网络连接等各种资源。
-
程序通常是静态的,不会发生改变,而进程是动态的,它的状态会随着时间的推移而不断变化。进程的状态包括运行、等待、就绪、挂起、终止等。
-
程序只是一段代码,它不能直接与外部环境交互,需要通过操作系统提供的接口来实现与外部环境的交互。而进程则可以直接与外部环境交互,包括与其他进程进行通信、共享文件、网络连接等。
-
程序只是一种抽象的概念,它不占用实际的计算机资源。而进程则需要占用计算机的资源,包括内存、CPU、硬盘等。
综上所述,程序和进程是两个不同的概念。程序是一组指令的集合,它是计算机执行任务的一种描述方式;而进程是正在执行的程序的实例,它包含了程序的代码、数据以及运行时的运行环境,是操作系统中资源分配的基本单位。
并行与并发
并行
并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行,所以无论从微观还是从宏观来看,二者都是一起执行的。
并发
并发(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。
并行与并发的区别
-
并行只能在多处理器系统中存在,而并发可以在单处理器和多处理器系统中都存在。
-
并行要求程序能够同时执行多个操作,而并发只是要求程序“看着像是”同时执行多个操作,其实是交替执行。
总结
并发针对单核 CPU 而言,它指的是 CPU 交替执行不同任务的能力;并行针对多核 CPU 而言,它指的是多个核心同时执行多个任务的能力。
单核 CPU 只能并发,无法并行;换句话说,并行只可能发生在多核 CPU 中。在多核 CPU 中,并发和并行一般都会同时存在,它们都是提高 CPU 处理任务能力的重要手段。
同步和异步
同步
同步,调用方调用某个东西,需要等待这个调用返回结果才能继续执行后续任务。
异步
异步,和同步相反,调用方调用某个东西,不用等待这个调用返回结果,就可以直接执行后续任务。