进程、线程与协程
千呼万唤Java的协程(虚拟线程/用户线程)随着JDK21的发布正式与开发人员见面了,因此在日常的开发中除了进程和线程又多了一个协程。
进程
进程是系统资源分配和调度的最小单位,系统运行一个程序就是一个进程从创建,运行到消亡的过程。进程通常包含内存资源、IO资源、信号处理等部分。
线程
线程是CPU调度的最小单位,线程包含在进程之中,是进程中实际作业的单位,在一个进程内通常包含有多个线程。相同进程内的所有线程共享该进程的全部系统资源。线程创建的开销主要是线程堆栈的建立,以及分配内存的开销,然而线程中最大的开销是发生在线程上下文切换的时候。基于作业位置,线程分为用户级线程和内核线程。
因为 Linux只有task_struct这一种描述进程的结构体。在内核看来只有进程而没有线程,线程调度时也是当做进程来调度的。Linux所谓的线程其实是与其他进程共享资源的轻量级进程
协程
协程随着go语言的goroutine而大放溢彩,是一种比线程更加轻量级的微线程。类比一个进程可以拥有多个线程,一个线程也可以拥有多个协程,因此协程又称微线程和纤程。在IO密集型条件下,使用多线程和多进程都会造成频繁切换调度的问题,严重消耗系统资源。线程的调度主要是由内核进行调度,而协程的调度完全由用户控制,并且协程拥有自己的寄存器上下文和栈,这部分都是在用户空间中,也避免了类似线程切换导致的频繁两态切换。
用户线程与内核线程概述
用户线程:
由用户空间程序管理和调度的线程,运行在用户空间,即专门提供应用程序使用的线程
内核线程:
由操作系统内核管理和调度的线程,运行在内核空间,即只有内核程序可以访问的线程
因此有一个总结:用户线程创建和切换成本低,但不可以利用多核。内核态线程,创建和切换成本高,可以利用多核
Java中的线程
在JDK默认的JVM即hotspot条件,JDK 1.2 之前,Java 的线程是基于绿色线程(Green Threads)实现,绿色线程是一种用户级线程(用户线程),依靠 JVM 自己模拟了多线程的运行而不依赖于操作系统。但是绿色线程和原生线程相比在使用时有一些限制,比如绿色线程不能直接使用操作系统提供的功能如异步 I/O、只能在一个内核线程上运行无法利用多核。因此,在 JDK 1.2 及以后,Java 线程改为基于原生线程(Native Threads)来实现,也就是说 JVM 直接使用操作系统原生的内核级线程(内核线程)来实现 Java 线程,由操作系统内核进行线程的调度和管理。所以,现在的JDK版本所谓的 Java 线程的本质其实就是操作系统的线程(除Solaris,Solaris系统原生支持多对多的线程模型,因此这个不绝对)。
Java中的协程
虚拟线程(Virtual Thread)是 JDK 实现的,而不是 OS 实现的轻量级线程(Lightweight Process,LWP),由 JVM 进行调度。一个操作系统线程对应多个虚拟线程,虚拟线程的因为可以共享操作系统线程,因此数量可以远大于操作系统的线程数量。JDK21 在 java.lang.Thread 包散列了两种类型的 Thread,一种是 platformThread,一种是 virtualThread。JVM 调度程序通过平台线程管理虚拟线程,多个虚拟线程挂载在一个平台线程上,因此一个平台线程可以在不同的时间执行不同的虚拟线程,当其中一个虚拟线程被阻塞或等待时,平台线程可以切换执行另一个虚拟线程。虚拟线程的开销轻量,使用后会立即销毁,因此也可以无需池化技术来节约开销。
概述并发与并行
并发:
两个及两个以上的作业在同一时间段内执行
并行:
两个及两个以上的作业在同一时刻执行
简述多线程切换
两个线程实现交替打印