面试官:Java线程可以无限创建吗?

news/2024/10/6 4:20:48/文章来源:https://www.cnblogs.com/xieshijie/p/18287499

Java线程无限创建

哈喽,大家好🎉,我是世杰。

⏩本次给大家介绍一下操作系统线程和Java的线程以及二者的关联

1. 面试连环call

  1. Java线程可以无限创建吗?
  2. Java线程和操作系统线程有什么关联?
  3. 操作系统为什么要区分内核态和用户态?

⏩要想解答这些问题,我们要先从操作系统线程开始说起,让我们开始吧🎉🎉🎉


2. 操作系统线程

2.1 内核态和用户态

根据进程访问资源的特点,我们可以把进程在系统上的运行分为两个级别:

  • 用户态(User Mode) : 用户态运行的进程可以直接读取用户程序的数据,拥有较低的权限

  • 内核态(Kernel Mode):内核态运行的进程几乎可以访问计算机的任何资源包括系统的内存空间、设备、驱动程序等,不受限制,拥有非常高的权限。当操作系统接收到进程的系统调用请求时,就会从用户态切换到内核态,执行相应的系统调用,并将结果返回给进程,最后再从内核态切换回用户态。

usermode-and-kernelmode

那为什么要区分用户态和内核态呢?

  • 在 CPU 的所有指令中,有一些指令是比较危险的比如内存分配设置时钟IO 处理等,如果所有的程序都能使用这些指令的话,会对系统的正常运行造成灾难性地影响。因此,我们需要限制这些危险指令只能内核态运行。这些只能由操作系统内核态执行的指令也被叫做 特权指令

  • 如果计算机系统中只有一个内核态,那么所有程序或进程都必须共享系统资源,例如内存、CPU、硬盘等,这将导致系统资源的竞争和冲突,从而影响系统性能和效率。并且,这样也会让系统的安全性降低,毕竟所有程序或进程都具有相同的特权级别和访问权限。

2.2 用户态线程

早期的操作系统中,所有的线程都是在用户态下实现,操作系统只能调度线程所属的进程,而无法调度线程

在这种模型下,用户需要自己定义线程的数据结构、创建、销毁、调度和维护等,这些线程运行在某个进程内,操作系统直接对进程进行调度

img

『优点』

  • 即使操作系统原生不支持线程,我们也可以通过库函数来支持线程
  • 线程的调度只发生在用户态,避免了操作系统从内核态到用户态的转换开销。

『缺点』

  • 由于操作系统无法调度线程,CPU 的时间片切换是以进程为维度的,如果进程中某个线程进行了耗时比较长的操作,那么由于用户态中没有时钟中断机制,就会导致此进程中的其它线程因为得不到 CPU 资源而长时间的持续等待;
  • 如果某个线程进行系统调用时比如缺页中断而导致了线程阻塞,此时操作系统也会阻塞整个进程,即使这个进程中其它线程还在工作。

2.3 内核态线程

现代操作系统,包括 Windows、Linux、Mac OS X 和 Solaris 等,都支持内核线程。线程运行在内核空间,直接由内核负责,由内核来完成调度。

此时我们可以直接使用操作系统中已经内置好的线程,线程的创建、销毁、调度和维护等,都直接由操作系统的内核来实现,我们只需要使用系统调用就好了,不需要像用户级线程那样自己设计线程调度。

img

内核线程和用户线程的对应关系并不完全是1对1,其关联模式有三种

2.4 线程模型

多对一线程模型

多个用户线程对应到同一个内核线程上,线程的创建、调度、同步的所有细节全部由进程的用户空间线程库来处理。这样,极大地减少了创建内核态线程的成本,但是线程不可以并行。因此,这种模型现在基本上用的很少。

img

『优点』

  • 用户线程的很多操作对内核来说都是透明的,不需要用户态和内核态的频繁切换。使线程的创建、调度、同步等非常快。

『缺点』

  • 由于多个用户线程对应到同一个内核线程,如果其中一个用户线程阻塞,那么该其他用户线程也无法执行
  • 内核并不知道用户态有哪些线程,无法像内核线程一样实现较完整的优先级调度等操作

一对一线程模型

该模型为每个用户态的线程分配一个单独的内核态线程,在这种情况下,每个用户态都需要通过系统调用创建一个绑定的内核线程。 这种模型允许所有线程并行执行,能够充分利用多核优势。目前 Linux 中的线程OpenJDK Java 线程等采用的都是一对一线程模型。每一个JVM线程,都有一个对应的内核线程。

img

『优点』

  • 解决了多对一模型的阻塞调度问题
  • 实现起来较为简单

『缺点』

  • 每创建一个用户线程,相应地就需要创建一个内核线程,开销较大,因此需要限制整个系统的线程数量
  • 对用户线程的大部分操作都会映射到内核线程上,引起用户态和内核态的频繁切换

多对多线程模型

这种模式下会为 n 个用户态线程分配 m 个内核态线程。m 通常小于 n。一种可行的策略是将 m 设置为核数。这种多对多的关系,减少了内核线程,同时也保证了多核心并行。多对多模型中线程的调度需要由内核态和用户态一起来实现,例如线程间同步需要用户态和内核态共同实现。用户态和内核态的分工合作导致实现该模型非常复杂。

PS: Linux多线程模型曾经也想使用该模型,但它太复杂,要对内核进行大范围改动,所以还是采用了一对一的模型

img

『优点』

  • 多对多模型将任意数量的用户线程复用到相同或更少数量的内核线程上,结合了一对一和多对一模型的最佳特性
  • 用户对创建的线程数没有限制

『缺点』

  • 实现起来非常复杂

3. Java 线程

3.1 线程库

在进入 Java 线程主题之前,有必要讲解一下线程库 Thread library 的概念。

线程库就是为开发人员提供创建和管理线程的一套 API。线程库不仅可以在用户空间中实现,还可以在内核空间中实现。前者涉及仅在用户空间内实现的 API 函数,没有内核支持。后者涉及系统调用,也就是说调用库中的一个 API 函数将会导致对内核的系统调用,并且需要具有线程库支持的内核。

下面简单介绍下三个主要的线程库:

  • POSIX线程:是[POSIX]的[线程]标准,定义了创建和操纵线程的一套[API]。实现POSIX线程标准的库常被称作pthreads,一般用于[Unix-like] POSIX系统,如[Linux]、 [Solaris]。

  • Win32 线程:用于 Window 操作系统的内核级线程库

  • Java 线程:Java 线程 API 通常采用宿主系统的线程库来实现,也就是说在 Win 系统上,Java 线程 API 通常采用 Win API 来实现,在 UNIX 类系统上,采用 Pthread 来实现。

3.1 Java线程模型

  • 在 JDK 1.2 之前,Java 线程是基于称为 "绿色线程"(Green Threads)的用户级线程实现的,JVM 开发了自己的一套线程库或者说线程管理机制。

  • 在 JDK 1.2 及以后,JVM 选择了更加稳定且方便使用的操作系统原生的内核级线程,通过系统调用,将线程的调度交给了操作系统内核。而对于不同的操作系统来说,它们本身的设计思路基本上是完全不一样的,因此它们各自对于线程的设计也存在种种差异,所以 JVM 中明确声明了:虚拟机中的线程状态,不反应任何操作系统中的线程状态

因此,现今 Java 中线程的本质,其实就是操作系统中的线程,其线程库和线程模型很大程度上依赖于操作系统(宿主系统)的具体实现,比如在 Windows 中 Java 就是基于 Wind32 线程库来管理线程,且 Windows 采用的是一对一的线程模型

3.2 Java线程创建数量

每个线程都有一个线程栈空间通过-Xss设置,可以通过JVM配置,JVM的默认栈大小

img

不考虑系统限制,可以通过如下公式计算,得出最大线程数量

线程数量=(机器本身可用内存-JVM分配的堆内存)/Xss的值

根据计算公式,得出如下结论:

  • 结论1:JVM堆越大,系统创建的线程数量越小。

  • 结论2:当-Xss的值越小,可生成线程数量越多。

假如我们的容器内存大小是8G,堆大小是4096M,走-Xss默认值,可以得出 最大线程数量:4096个。

我们知道操作系统分配给每个进程的内存大小是有限制的,比如32位的Windows是2G。因此操作系统对一个进程下的线程数量是有限制的,不能无限的增多。

如果考虑系统限制,主要跟以下几个参数有关系

  • /proc/sys/kernel/pid_max 增大,线程数量增大,pid_max有最高值,超过之后不再改变,而且32,64位也不一样

  • /proc/sys/kernel/thread-max 系统可以生成最大线程数量

线程是非常宝贵的资源,我们要严格控制线程的数量


『引用』:

Threads

Java 线程和操作系统的线程有啥区别?

一台 Java 服务器可以跑多少个线程?

操作系统常见面试题总结(上)

用户态线程和内核态线程的区别

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

标准IO与系统IO

C平台的标准IO(可跨系统)Linux 系统IO (Linux系统平台才能使用)Linux系统的IO(输入输出)特点主要包括以下几个方面 1)文件视为一切:在Linux中,几乎所有的设备和资源都被视为文件。这意味着无论是硬件设备(如磁盘、网络接口)还是系统资源(如进程、内存),它们都可以通…

比snipaste更好用的截图工具 pixpin

pixpin官网功能介绍与 snipaste 的功能相似,比snipaste好用作者:mohistH 出处:https://www.cnblogs.com/pandamohist/ 本文版权归作者和博客园共有,谢绝一切形式的转载,否则将追究法律责任。

HT-014 Div3 扫雷 题解 [ 绿 ] [ 二维差分 ]

分析 观察到是曼哈顿距离 \(\le r\) 的范围可以扫到,联想到如下图形:左边是 \(r=1\) 可以扫到的范围,右边是 \(r=2\) 可以扫到的范围。 于是,我们只要对这样的图形在 \(1000*1000\) 的格子里差分一下就好了 。 但这样的复杂度是 \(O(nm)\) 的,会死的很惨。 优化 不难发现这…

[VSCode] Add all missing import

https://github.com/microsoft/vscode-docs/blob/vnext/release-notes/v1_46.md#add-all-missing-imports-source-action

秒杀圣经:10Wqps高并发秒杀,16大架构杀招,帮你秒变架构师

文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 :《尼恩Java面试宝典》 持续更新+ 史上最全 + 面试必备 2000页+ 面试必备 + 大厂必备 +涨薪必备 免费赠送 :《尼恩技术圣经+高并发系列PDF》 ,帮你 实现技术自由,…

《从零开始学习Python爬虫:顶点小说全网爬取实战》

文章优势:最新内容更新:最近几天整理,包含最新的爬虫技术和实践经验。 精致内容汇总:基于培训课程笔记,内容丰富、详细,适合初学者入门及进阶。顶点小说 装xpath helper GitHub - mic1on/xpath-helper-plus: 这是一个xpath开发者的工具,可以帮助开发者快速的定位网页元素…

LRU算法简介

LRU(Least Recently Used,最近最少使用)算法是一种常用于缓存管理的算法,用于在缓存空间有限的情况下,决定哪些数据应该被移除。它的基本思想是:如果一个数据最近被访问过,那么在将来一段时间内它被再次访问的概率较高。因此,当缓存已满,需要移除数据时,优先移除那些…

数据结构小学期第六天

今天完全实现了九宫格拼图游戏,具备一键通关功能按下W键,查看原图功能按住A键不松,移动图片按上下左右键,如果你自己想要实现这个功能,需要自己的图片,图片格式要求。 每个小图片是105*105,完整图片是315*315.有人想要做一下,可以试一试。代码如下 启动类1 import com.…

1、flask-基本架构-MVT - 虚拟环境的安装 - 创建flask应用

flask基本架构图 创建虚拟环境 #1. 打开cmd或pycharm都可以(确保安装python环境) #2. 安装虚拟环境模块-windows - pip install virtualenv virtualenvwrapper-win#3. 查看虚拟环境 - workon#4. 创建虚拟环境 - mkvirtualenv flask2env - 默认创建在:C:\Users\Administrato…

基于Qwen2/Lllama3等大模型,部署团队私有化RAG知识库系统的详细教程(Docker+AnythingLLM)

大语言模型在垂直细分领域存在知识局限、幻觉、数据安全等一些问题,可通过RAG(检索增强生成)方案来解决。本文基于AnythingLLM框架,搭建团队私有知识库系统,并进行使用和验证,RAG系统在保留输出的有效性同时,还保留了创造性……自 ChatGPT 发布以来,大型语言模型(Larg…

基于STM32F1系列,驱动L298N电机驱动板实现直流电机的启动、停止、调速功能

一. L298N电机驱动板电源引脚 VCC 外接直流电源引脚,电压范围在5~35V之间 GND GND是接地引脚,连接到电源负极 5V 驱动芯片内部逻辑供电引脚,如果安装了5V跳帽,则此引脚可输出5V电压,为微控板或其他电路提供电力供给,如果拔掉5V跳帽,则需要独立外接5V电源 控制引脚 IN1 &…

SpringBoot引入WebSocket

WebSocket 是一种在客户端和服务器之间提供低延迟、全双工通信的网络协议。它允许双方在建立一次连接后,进行实时、持续的数据交换,无需像HTTP那样为每一个请求和响应建立新的连接。WebSocket的设计初衷是解决传统HTTP协议在实时通信方面的不足,比如实现实时聊天、游戏、股票…