高并发必备篇(三):线程的内存模型(上)

52 篇文章 0 订阅
24 篇文章 0 订阅

上一篇文章中我们提到了Java代码运行的步骤中需要把变量从主内存中读取,计算修改完之后又需要写回主内存,那么这里面就涉及到了JVM(java虚拟机)内存的结构。

 

而想要深层次的了解并发和解决并发问题的影响并能够更充分的利用计算机处理器的效能,那么我们就需要对硬件内存架构、操作系统的线程模型以及JVM的内存进行了解才行,所以下面我们也是围绕这三个方面来讲解。

 

 

1.硬件内存架构

我们知道计算机中程序运行都需要依赖计算机中非常重要的一个硬件就是CPU(中央处理器)。早期CPU由运算器和控制器组成;控制器主要负责程序计数、指令寄存和译码等,计算器主要是算术逻辑单元运算和测试等。

 

但是CPU的运行计算速度太快了,而其他硬件比如IO操作(数据读取和写入)、网络、内存读取等等,跟cpu的速度比起来是差几个数量级的。

 

如果不做处理,那么cpu和各个硬件之间的速度差异就非常明显,在处理程序的时候cpu很快就处理完并一直处于等待状态,这样就无法充分利用CPU的效能,浪费资源。

 

所以现代计算机系统都不得不加入一层读写速度尽可能接近处理器运算速度的高速缓存cache部分来作为数据缓冲区,并且高速缓存也做了多级缓存用于充分的数据缓冲。

 

例如现在的CPU大都是分L1一级缓存、L2二级缓存和L3三级缓存(运行速度L1,L2,L3依次降低),用于补偿CPU和内存、外围设备之间在操作速度上的差别。

 

程序运行时将运算需要使用到的数据复制到缓存中,让运算能快速进行,当运算结束之后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了。

 

 

这种设计在单核CPU中是没有问题的,但是如果是多核CPU就必须考虑另外一个问题了就是:缓存一致性(Cache Coherence),即如何解决在多个处理器的运算任务都涉及同一块主内存区域时,将可能导致各自缓存数据不一致的问题。

 

为了解决这个问题就加入了一些协议用于保证缓存的一致性,这类协议有MSI、MESI、等。高速缓存交互设计如下:

 

 

不同结构的物理机器可以拥有不一样的内存模型,而JVM也有自己的内存模型。

 

除了增加高速缓存之外,为了使得处理器内部的运算单位能尽量被充分利用,处理器可能会对输入代码进行乱序执行优化,处理器会在计算之后将乱序执行的结果重组,保证该结果与顺序执行的结果是一致的,但并不保证程序中各个语句计算的先后顺序与输入代码中的顺序一致(类似JVM的指令重排)。

 

 2.操作系统中的多线成模型

之前提到过线程是CPU调度的最小单位,可以独立的完成任务。而操作系统中想要实现多线程,主要使用3种多线程模型:

 

● 内核线程模型

● 用户线程模型

● 混合线程模型

 

① 内核线程模型

Kernel-Level Thread 简称KLT,内核线程模型完全依赖于操作系统内核,内核保存线程的状态和信息,线程的创建、调度和管理由内核完成,并且系统内核负责将多个线程执行的任务映射到各个CPU中去执行。

 

用户的应用进程中的线程也是通过一对一的使用系统内核提供的轻量级进程LWP(Light weight process)接口来使用系统内核线程。

 

这种模型的好处是LWP在调用过程中即使阻塞了也不会影响整个进程的执行;

 

缺点是各种线程的操作都需要在用户态和内核态之间频繁切换,消耗太大,速度相对用户线程模型来说要慢。

 

 

② 用户线程模型

User-Level Thread 简称ULT,用户线程模型不依赖操作系统核心,应用提供创建、同步、调度和管理线程函数来控制用户线程。不需要线程从用户态到内核态切换,速度快。

 

这种设计的好处是线程的各种操作以及切换消耗很低;

缺点是线程的所有操作都需要在用户态实现,线程的调度实现起来异常复杂,并且系统内核对ULT无感知,如果线程阻塞则会引起整个进程的阻塞。

 

 

③ 混合线程模型

混合线程模型是内核线程和用户线程的混合使用,用户线程仍然是在用户态中创建,用户线程的创建、切换和销毁的消耗很低,用户线程的数量不受限制。而LWP在用户线程和内核线程之间充当桥梁,就可以使用操作系统提供的线程调度和处理器映射功能。

 

 

我们 JVM虚拟机中的线程模型就是基于操作系统提供的原生线程模型来实现的,而不同的操作系统导致JVM中线程的模型不同,比如Windows系统和Linux系统都是使用的内核线程模型,而Solaris系统支持用户内核混合线程模型和内核线程模型两种实现。

 

下面我们来验证下windows下java是内核线程还是用户线程:

 

在启动100个线程之前,查看下windows系统内核的线程数:

 

 

启动100个线程之后,windows系统内核线程数:

 

 

发现我们java线程和系统内核增加的线程数量几乎一致的,所以windows系统下java线程是内核线程的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值