并发编程从操作系统底层工作整体认识开始( 四 )


  • step1:CPU从ring3切换ring0创建线程
  • step2:创建完毕,CPU从ring0切换回ring3
  • step3:线程执行JVM程序
  • step4:线程执行完毕 , 销毁还得切会ring0
操作系统内存管理执行空间保护操作系统有用户空间与内核空间两个概念 , 目的也是为了做到程序运行安全隔离与稳定 , 以32位操作系统4G大小的内存空间为例
并发编程从操作系统底层工作整体认识开始文章插图
Linux为内核代码和数据结构预留了几个页框 , 这些页永远不会被转出到磁盘上 。 从 0x00000000 到 0xC0000000(PAGE_OFFSET) 的线性地址可由用户代码 和 内核代码进行引用(即用户空间) 。 从0xC0000000(PAGE_OFFSET)到 0xFFFFFFFFF的线性地址只能由内核代码进行访问(即内核空间) 。 内核代码及其数据结构都必须位于这 1 GB的地址空间中 , 但是对于此地址空间而言 , 更大的消费者是物理地址的虚拟映射 。
这意味着在 4 GB 的内存空间中 , 只有 3 GB 可以用于用户应用程序 。 进程与线程只能运行在用户方式(usermode)或内核方式(kernelmode)下 。 用户程序运行在用户方式下 , 而系统调用运行在内核方式下 。 在这两种方式下所用的堆栈不一样:用户方式下用的是一般的堆栈(用户空间的堆栈) , 而内核方式下用的是固定大小的堆栈(内核空间的对战 , 一般为一个内存页的大小) , 即每个进程与线程其实有两个堆栈 , 分别运行与用户态与内核态 。
由空间划分我们再引申一下 , CPU调度的基本单位线程 , 也划分为:
  1. 内核线程模型(KLT)
  2. 用户线程模型(ULT)
内核线程模型
并发编程从操作系统底层工作整体认识开始文章插图
内核线程(KLT):系统内核管理线程(KLT),内核保存线程的状态和上下文信息 , 线程阻塞不会引起进程阻塞 。 在多处理器系统上 , 多线程在多处理器上并行运行 。 线程的创建、调度和管理由内核完成 , 效率比ULT要慢 , 比进程操作快 。
用户线程模型
并发编程从操作系统底层工作整体认识开始文章插图
用户线程(ULT):用户程序实现,不依赖操作系统核心,应用提供创建、同步、调度和管理线程的函数来控制用户线程 。 不需要用户态/内核态切换 , 速度快 。 内核对ULT无感知 , 线程阻塞则进程(包括它的所有线程)阻塞 。
到这里 , 大家不妨思考一下 , jvm是采用的哪一种线程模型?
进程与线程什么是进程?现代操作系统在运行一个程序时 , 会为其创建一个进程;例如 , 启动一个Java程序 , 操作系统就会创建一个Java进程 。 进程是OS(操作系统)资源分配的最小单位 。
什么是线程?线程是OS(操作系统)调度CPU的最小单元 , 也叫轻量级进程(Light Weight Process) , 在一个进程里可以创建多个线程 , 这些线程都拥有各自的计数器、堆栈和局部变量等属性 , 并且能够访问共享的内存变量 。 CPU在这些线程上高速切换 , 让使用者感觉到这些线程在同时执行 , 即并发的概念 , 相似的概念还有并行!
线程上下文切换过程:
并发编程从操作系统底层工作整体认识开始文章插图
虚拟机指令集架构虚拟机指令集架构主要分两种:
  1. 栈指令集架构
  2. 寄存器指令集架构
关于指令集架构的wiki详细说明:指令集架构
栈指令集架构
  1. 设计和实现更简单,适用于资源受限的系统;
  2. 避开了寄存器的分配难题:使用零地址指令方式分配;
  3. 指令流中的指令大部分是零地址指令,其执行过程依赖于操作栈,指令集更小,编译器容易实现;
  4. 不需要硬件支持,可移植性更好,更好实现跨平台 。
寄存器指令集架构
  1. 典型的应用是x86的二进制指令集:比如传统的PC以及Android的Davlik虚拟机 。
  2. 指令集架构则完全依赖硬件,可移植性差 。
  3. 性能优秀和执行更高效 。
  4. 花费更少的指令去完成一项操作 。
  5. 在大部分情况下,基于寄存器架构的指令集往往都以一地址指令、二地址指令和三地址指令为主,而基于栈式架构的指令集却是以零地址指令为主 。
Java符合典型的栈指令集架构特征 , 像Python、Go都属于这种架构 。
【并发编程从操作系统底层工作整体认识开始】文章持续更新 , 可以公众号搜一搜「 一角钱技术 」第一时间阅读 ,本文 GitHub org_hejianhui/JavaStudy 已经收录 , 欢迎 Star 。