【Java笔记】多线程0:JVM线程是用户态还是内核态?Java 线程与OS线程的联系

文章目录

  • JVM线程是用户态线程还是内核态线程
    • 什么是用户态线程与内核态线程
    • 绿色线程
      • 绿色线程的缺点
    • 线程映射
      • 稍微回顾下线程映射模型
      • JVM线程映射
  • 线程状态
    • 操作系统的线程状态
    • JVM的线程状态
    • JVM线程与OS线程的状态关系
  • Reference

今天复盘一下Java中,JVM线程与实际操作系统中线程的一些联系
请先思考下面问题:

JVM线程是用户态线程还是内核态线程

什么是用户态线程与内核态线程

先简单回顾下几个概念:

用户线程(User Thread):在用户空间实现的线程,不是由内核管理的线程,是由用户态的线程库来完成线程的管理;
内核线程(Kernel Thread):在内核中实现的线程,是由内核管理的线程

可能有朋友觉得,Java线程都是我们用户new出来的,应该是用户态吧?
这种感觉肯定是错的,因为用户也可以完成一些内核态操作,比如通过命令行来进行命令调用与shell脚本。

先说一下结论:早期Java的“绿色线程”是用户态线程,现在则是通过1:1线程映射模型映射到内核态线程。

绿色线程

在古早版本中(jdk1.2之前),Java的一个特大卖点就是跨平台特性,也就是那个经典口号:“Write once, run anywhere”。但那个时候有些平台还没提供本地线程的支持,无法将用户线程映射到OS线程。所以那会采用的是“绿色线程”(Green Threads),也就是在虚拟平台上模拟出“内核线程”。

而绿色线程运行在用户空间,通过第三方library或者VM进行调度,可以说属于用户态线程

绿色线程的缺点

前面说了,绿色线程无法将用户线程映射为内核线程,只是在用户空间的模拟,对于造作系统来说都属于一个进程,仅有一个并发的概念,不能发挥多核CPU的优势去实现真正并行

线程映射

稍微回顾下线程映射模型

用户态线程是可以准备好程序让内核态线程执行,因此需要一些模型来实现用户线程和内核线程的对应关系:

  • One to One:一个用户线程对应一个内核线程,一旦用户线程停止,两个线程都会离开OS
    • 缺点:
      • 操作系统限制了内核线程的数量
      • 操作系统内核线程调度时,上下文切换的开销较大(相比于其他映射模型),导致用户线程的执行效率下降
  • Many to One:多个用户线程对应一个内核线程,用户线程间的切换由用户态代码实现
    • 优点:相对一对一模型,多对一模型的线程切换速度要快许多,并且数量不受OS内核线程数的影响
    • 缺点:
      • 如果其中一个用户线程阻塞,时内核线程也随之阻塞,其他用户线程也无法执行
      • 在多处理器系统上,处理器数量的增加对多对一模型的线程性能不会有明显的增加,因为所有的用户线程都映射到一个处理器上了
  • Many to Many:多个用户线程对应到多个内核线程,内核线程数M可以小于用户态线程数N
    • 优点:(解决了前两个的缺点)
      • 一个用户线程的阻塞不会导致所有线程的阻塞
      • 对用户线程的数量没有限制,
      • 在多处理器的操作系统中,多对多模型的线程也能得到一定的性能提升,但提升的幅度不如一对一模型的高

JVM线程映射

由于绿色线程仅仅是线程概念的用户态模拟,不能并行,因此后来换成了映射的方式来将JVM线程映射到OS内核线程。

现在,每个Java线程都映射到操作系统中一个完全独立的线程(一般是One to One),其创建销毁等工作都通过内核操作完成。

线程状态

操作系统的线程状态

操作系统的线程可描述为五种状态:new、ready、run、block、end

JVM的线程状态

JVM线程可描述为六种状态,在Thread中有个枚举类型,即Thread.state:

public enum State {
    NEW,
    RUNNABLE,
    BLOCKED,
    WAITING,
    TIMED_WAITING,
    TERMINATED;
}
  • NEW:即线程刚创建,但未start()启动时的状态
  • RUNNABLE:表示当前线程正在运行。此时有两种可能:
    • 就绪状态:
      • start():启动线程,进入就绪状态,等待调度程序调度
      • 当前线程sleep()结束,或是其他线程join()结束
      • yield()出让线程
    • 运行中状态:
      • 线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态(也是线程进入运行中状态的唯一方法)
  • BLOCKED:在进入synchronized关键字修饰的方法或代码块(获取锁)时的状态,阻塞等待其他线程释放锁
  • WAITING:调用一些方法后会进入或设计等待状态,比如
    • Object.wait():使当前线程处于等待状态直到另一个线程通过notify()显式唤醒它;
    • Thread.join():插队,等待线程执行完毕,底层调用的是Object实例的wait方法;
    • LockSupport.park():除非获得调用许可,否则禁用当前线程进行线程调度。
    • 处于等待状态的
  • TIMED_WAITING:与WAITING类似,但是有指定的等待时间,比如:
    • Thread.sleep(long millis):使当前线程睡眠指定时间
    • Object.wait(long timeout):线程休眠指定时间,等待期间可以通过notify()/notifyAll()唤醒;
    • Thread.join(long millis):等待当前线程最多执行millis毫秒,如果millis为0,则会一直执行;
    • 上述三种方法使线程等待后,可以通过Interrupt()显示唤醒(中断等待)
  • TERMINATED:run()方法完成时或者主线程main()方法完成时,线程就会关闭终止
    • 在一个终止的线程上调用 start() 方法,会抛出 java.lang.IllegalThreadStateException 异常

另外,我们可以通过创建线程的getState()方法获取当前线程状态,或者感兴趣的朋友可以去了解下Jstack怎么做线程状态分析,可以用来排查死锁或者一些CPU占用过高的问题

JVM线程与OS线程的状态关系

Java线程的状态只会因为自身程序执行而发生转变,一般内核不会改变JVM线程状态

JVM线程与OS线程不一定是对应的,需要通过映射完成:

  • NEW 创建状态,对应OS线程的创建状态 new

  • TERMINATED 销毁状态,对应OS线程的销毁状态 end

  • RUNNABLE 运行状态,对应OS线程的run运行状态ready就绪状态:只要操作系统正在运行,JVM就判定线程为run,并不一定对应内核线程的run状态。

    • 有时,OS线程阻塞,单JVM看来OS仍在运行。比如Scanner.in与Scoket.accpet等待输入时,JVM线程还是run状态,而其映射的内核线程状态是wait
  • WAITING 等待状态,对应OS线程的wait状态:一般是由于调用了wait一类的方法陷入等待。

    • wait的作用-线程协作机制:

      线程间并不都是竞争关系,也有协作关系。比如,一般一个进程中的多个线程除了普通线程外,还包括消耗线程、增加线程。消耗线程与增加线程间就是协作关系(生产者与消费者),所以需要wait,然后用notify特定唤醒,如果不特定唤醒,则会陷入线程的忙等待(比如说消耗线程没数据消费了,但是生产线程一直竞争不到执行权,没法生产新数据,消耗线程就一直等着)

      注意一下,wait通过notify唤醒后并不会立即执行,而是跟其他线程一起重新竞争锁 资源
      请添加图片描述

  • TIMED_WAITING 定时等待,对应OS线程的:相当于有限时间的wait,通过sleep等方式转变,通过interrupt打断。

    • sleep时会有锁的释放吗?

      不会,sleep本身与并发关系不大,不会进行锁操作,此时如果有synchronized同步块,其他线程仍然不能访问共享数据。

  • BLOCKED 无法获取锁时的阻塞,就对应OS的block状态

    • WAITINGBLOCKED 的区别,一个是主动,一个是被动

Reference

https://www.runoob.com/java/thread-status.html
http://concurrent.redspider.group/article/01/4.html
https://www.bilibili.com/video/BV172421P7MB/?share_source=copy_web&vd_source=e40b707ba9b46ace5a15c44fb5fa3388
https://juejin.cn/post/7016228406220029983
https://www.zhihu.com/question/64100112/answer/218379442

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/516826.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

面试算法-140-接雨水

题目 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,0,2,1,0,1,3,2…

Java web第一次作业

1.学会用记事本编写jsp文件&#xff0c;并放进tomcat的相关目录下&#xff0c;运行。 源代码&#xff1a; <% page contentType"text/html;charsetUTF-8" language"java" %> <html> <head> <title>我的第一个JSP页面</ti…

在深度学习模型中引入先验

当面对复杂问题的时候&#xff0c;在深度学习模型提取特征的过程中完全抛弃知识是非常不明智的策略。虽然有很多研究者在深度网络处理数据之前&#xff0c;利用具有某种知识的模型驱动方法对数据进行预处理&#xff0c;但是这种方法没有进行实质性地改造深度网络&#xff0c;且…

组合总和 II-java

题目描述: 给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意&#xff1a;解集不能包含重复的组合。 解题思想: 回溯法 剪枝 : …

PWM技术的应用

目录 PWM技术简介 PWM重要参数 PWM实现呼吸灯 脉宽调制波形 PWM案例 电路图 keil文件 直流电机 直流电机的控制 直流电机的驱动芯片L293D L293D引脚图 L293D功能表 直流电机案例 电路图 keil文件 步进电机 步进电机特点 步进电机驱动芯片L298 L298引脚图 L…

【Canvas与艺术】绘制黑白纹章,内嵌陶渊明南山诗

【效果图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>用Canvas绘制黑白纹章</title><style type"text/css…

Doris实践——信贷系统日志分析场景的实践应用

目录 前言 一、早期架构演进 1.1 架构1.0 基于Kettle MySQL离线数仓 1.2 架构2.0 基于 Presto / Trino统一查询 二、基于Doris的新一代架构 三、新数仓架构搭建经验 3.1 并发查询加速 3.2 数仓底座建设 四、Doris助力信DolphinScheduler 和 Shell 贷业务场景落地 4.…

QT----opencv4.8.0编译cuda版本,QTcreater使用

目录 1 编译opencv4.8.02 验证能否加载GPU cuda12.1 opencv4.8.0 vs2019 cmake3.29 1 编译opencv4.8.0 打开cmake&#xff0c;选择opencv480路径&#xff0c;build路径随意 点击configure后&#xff0c;选择这些选项&#xff0c;opencv_word&#xff0c;cuda全选&#xff0c;…

一款功能强大且易于使用的视频剪辑应用程序

一款功能强大且易于使用的视频剪辑应用程序&#xff0c;它提供了丰富多样的转场特效和滤镜&#xff0c;让用户能够轻松地为视频添加各种炫酷的效果。与其他视频编辑软件相比&#xff0c;剪映国际版的最大亮点在于其完全免费使用。首先&#xff0c;剪映国际版为用户提供了丰富的…

pth转onnx,同时使用onnx进行部署

当像我一样的菜鸡在使用开源的深度学习代码时&#xff0c;对于输出的pth模型文件&#xff0c;在预测时使用开源的predict.py文件进行部署&#xff0c;但是使用pth文件有一个问题&#xff0c;就是每次他都要重新加载一次模型&#xff0c;而且不方便移植&#xff0c;所以&#xf…

Java 面向对象(基础)

1、面向对象的概述及两大要素&#xff1a;类与对象 1. 面向对象内容的三条主线&#xff1a; - Java类及类的成员&#xff1a;&#xff08;重点&#xff09;属性、方法、构造器&#xff1b;&#xff08;熟悉&#xff09;代码块、内部类 - 面向对象的特征&#xff1a;封装、继承…

31-数据流:通过iam-authz-server设计,看数据流服务的设计

IAM数据流服务iam-authz-server的设计和实现。 iam-authz-server的功能介绍 iam-authz-server目前的唯一功能&#xff0c;是通过提供 /v1/authz RESTful API接口完成资源授权。 /v1/authz 接口是通过github.com/ory/ladon来完成资源授权的。 因为iam-authz-server承载了数据流…

ES6展开运算符

1.展开可迭代对象&#xff08;简单理解为数组和伪数组&#xff09;&#xff0c;如数组、 NodeList 、arguments。 可以通过展开运算符把一个伪数组转换为数组 const a [...document.body.children]; console.log(a); console.log(Array.isArray(a));2.实现数组的浅拷贝 cons…

51单片机入门之独立按键

目录 1.按键简介 2.独立按键控制LED亮灭 3.独立按键控制LED移位 1.按键简介 在生活中&#xff0c;我们常常会见到各种按键&#xff0c;我们的开发板上也有按键&#xff0c;就在左下角有四个按键&#xff0c;我们把它们叫做独立按键。 独立按键的原理比较简单&…

【三十三】【算法分析与设计】回溯(1),46. 全排列,78. 子集,没有树结构,但是依旧模拟树结构,回溯,利用全局变量+递归函数模拟树结构

46. 全排列 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1&#xff0c;2&#xff0c;3] 输出&#xff1a;[[1&#xff0c;2&#xff0c;3]&#xff0c;[1&#xff0c;3&a…

WPF中通过自定义Panel实现控件拖动

背景 看到趋时软件的公众号文章&#xff08;WPF自定义Panel&#xff1a;让拖拽变得更简单&#xff09;&#xff0c;发现可以不通过Drag的方法来实现ListBox控件的拖动&#xff0c;而是通过对控件的坐标相加减去实现控件的位移等判断&#xff0c;因此根据文章里面的代码,边理解边…

考题抄错会做也白搭--模版方法模式

1.1 选择题不会做&#xff0c;蒙呗&#xff01; "题目抄错了&#xff0c;那就不是考试题目了&#xff0c;而考试试卷最大的好处就是&#xff0c;大家都是一样的题目&#xff0c;特别是标准化的考试&#xff0c;比如全是选择或判断的题目&#xff0c;那就最大化地限制了答题…

整合Mybatis(Spring学习笔记十二)

一、导入相关的包 junit 包 Mybatis包 mysql数据库包 Spring相关的包 Aop相关的包 Mybatis-Spring包&#xff08;现在就来学这个&#xff09; 提示jdk版本不一致的朋友记得 jdk8只支持spring到5.x 所以如果导入的spring(spring-we…

Linux:进程终止和等待

一、进程终止 main函数的返回值也叫做进程的退出码&#xff0c;一般0表示成功&#xff0c;非零表示失败。我们也可以用不同的数字来表示不同失败的原因。 echo $?//打印最近一次进程执行的退出码 而作为程序猿&#xff0c;我们更需要知道的是错误码所代表的错误信息&#x…

【智能算法】磷虾群算法(KHA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2012年&#xff0c;Gandomi等人受到自然界中磷虾生存行为启发&#xff0c;提出了磷虾群算法&#xff08;Krill Herd Algorithm, KHA&#xff09;。 2.算法原理 2.1算法思想 KHA受南极鳞虾群觅食行…