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

news2025/1/12 1:39:06

文章目录

  • 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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大模型学习笔记一

前言 随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 一、AI是什么? 二、大模型能干什么 大模型,全称「大语言模型」,英文「Large…

栈的应用——用栈实现算数混合运算表达式的计算

1、单目运算符双目运算符 算数运算符分为单目运算符和双目运算符等 单目运算符只需要一个操作数,双目运算符需要两个操作数 双目运算符最常见:常见的算术运算符:*/,比较运算符:<>=等等以下是一些单目运算符:正号 (+): 用于表示正数或给数值一个正号。例如:+5 仍然…

MySql 实战大数据查询-(表分区实现)

一 mysql分区&#xff1a; 分区是将单个表按照某种规则划分成多个子集&#xff0c;每个子集称为一个分区。常见的分区策略包括按照时间范围、范围值、列表等进行分区。 优点&#xff1a; 查询性能更好&#xff0c;涉及分区键的查询&#xff0c;数据库引擎可以只扫描特定分区&…

最优算法100例之30-表示数值的字符串

专栏主页&#xff1a;计算机专业基础知识总结&#xff08;适用于期末复习考研刷题求职面试&#xff09;系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 请实现一个函数用来判断字符串是否表示数值&#xff08;包括整数和小数&#xff09;。例如&a…

卷积篇 | YOLOv8改进之引入全维度动态卷积ODConv | 即插即用

前言:Hello大家好,我是小哥谈。ODConv是一种关注了空域、输入通道、输出通道等维度上的动态性的卷积方法,一定程度上讲,ODConv可以视作CondConv的延续,将CondConv中一个维度上的动态特性进行了扩展,同时了考虑了空域、输入通道、输出通道等维度上的动态性,故称之为全维度…

LeetCode第六题:Z 字形变换 【6/1000 python】

&#x1f464;作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任大厂数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python 作者专栏每日更新&#xff1a; LeetCode解锁1000题: 打怪升级之旅 LeetCode解锁1000题: 打怪升级之旅htt…

springboot实战---7.springboot制作Docker镜像

&#x1f388;个人主页&#xff1a;靓仔很忙i &#x1f4bb;B 站主页&#xff1a;&#x1f449;B站&#x1f448; &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;SpringBoot &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&…

七、Promethus监控系统

一、普罗米修斯监控系统 1、为什么需要监控&#xff1a; ① 实时收集数据&#xff1a;监控工具能够实时收集关于系统、应用、网络等各方面的数据&#xff0c;包括性能指标、错误日志、用户行为等。 ② 及时发现问题&#xff1a;通过实时数据收集和分析&#xff0c;监控系统能…

带头双向循环链表,顺序表和链表的比较

双向链表 单链表结点中只有一个指向其后继的指针&#xff0c;使得单链表只能从前往后依次遍历&#xff0c;要访问某个结点的前驱&#xff08;插入、删除操作时&#xff09;&#xff0c;只能从头开始遍历&#xff0c;访问前驱的时间复杂度为O(N)。为了克服这个缺点&#xff0c;…

SSM实战项目——哈哈音乐(二)后台模块开发

1、项目准备 ① 引入后台模块&#xff08;hami-console&#xff09;需要的依赖 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0…

金融贷款批准预测项目

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 在金融服务行业&#xff0c;贷款审批是一项关键任务&#xff0c;它不仅关系到资金的安全&#xff0c;还直接影响到金融机构的运营效率和风险管理…

LIN总线基础

文章目录 1 什么是LIN 总线&#xff1f;1.1 LIN总线的历史 2.LIN总线的特点3. 应用4 LIN总线基本概念4.1 LIN报文帧结构4.1.1 主节点与从节点4.1.2 调度表4.1.3网络管理4.1.4 帧头结构4.1.4.1 电平 1 什么是LIN 总线&#xff1f; LIN(Local Interconnect Network)是一种低成本…

linux 搭建Samba服务

Samba简介 SAMBA是⼀个实现不同操作系统之间⽂件共享和打印机共享的⼀种SMB协议的免费软件&#xff0c; SMB(Server Message block)协议是window下所使⽤的⽂件共享协议&#xff0c;我们在linux系统或 者其类unix系统当中可以通过samba服务来实现SMB功能。 &#xff08;1&…

Linux离线安装python3(源码编译)

1、下载python包 下载python3.9.6的源码包 python下载 下载后&#xff0c;解压&#xff0c;目录如下&#xff1a; -rw-------. 1 root root 1454 Aug 26 2023 anaconda-ks.cfg -rw-r--r--. 1 root root 25640094 Apr 4 21:52 Python-3.9.6.tgz drwxrwxr…

LC 96.不同的二叉搜索树

96.不同的二叉搜索树 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a; n 3 输出&#xff1a; 5 示例 2&#xff1a; 输入&#xff1a;…

配置启动nacos,保姆级教程

下载nacos 下载链接 https://github.com/alibaba/nacos/releases进去下拉&#xff0c;找到下载版本信息。 下载后如图所示。 配置数据库 在我们的conf文件夹中有一个nacos-mysql的数据库文件 我们需要导入数据库&#xff0c;可通过工具Navicat等进行导入。 会有一下几张表…

【面试经典150 | 动态规划】交错字符串

文章目录 写在前面Tag题目来源解题思路方法一&#xff1a;动态规划 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等内容进行…

JAVA毕业设计133—基于Java+Springboot+Vue的网上宠物店商城管理系统(源代码+数据库+12000字论文)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootVue的网上宠物店商城管理系统(源代码数据库12000字论文)133 一、系统介绍 本项目前后端分离&#xff0c;分为管理员、用户两种角色 1、用户&#xff1a; 注册…

聚合DNS管理系统v1.0全新发布 域名解析管理系统

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 聚合DNS管理系统可以实现在一个网站内管理多个平台的域名解析&#xff0c;目前已支持的域名平台有&#xff1a;阿里云、腾讯云、华为云、西部数码、CloudFlare。本系统支持多用户&…

数据挖掘中的PCA和KMeans:Airbnb房源案例研究

目录 一、PCA简介 二、数据集概览 三、数据预处理步骤 四、PCA申请 五、KMeans 聚类 六、PCA成分分析 七、逆变换 八、质心分析 九、结论 十、深入探究 10.1 第 1 步&#xff1a;确定 PCA 组件的最佳数量 10.2 第 2 步&#xff1a;使用 9 个组件重做 PCA 10.3 解释 PCA 加载和特…