Java 线程和操作系统的线程有啥区别?
尽人事,听天命。博主东南大学硕士在读,携程 Java 后台开发暑期实习生,热爱健身和篮球,乐于分享技术相关的所见所得,关注公众号 @ 飞天小牛肉,第一时间获取文章更新,成长的路上我们一起进步
本文已收录于 「CS-Wiki」Gitee 官方推荐项目,现已累计 1.6k+ star,致力打造完善的后端知识体系,在技术的路上少走弯路,欢迎各位小伙伴前来交流学习
如果各位小伙伴春招秋招没有拿得出手的项目的话,可以参考我写的一个项目「开源社区系统 Echo」Gitee 官方推荐项目,目前已累计 700+ star,基于 SpringBoot + MyBatis + MySQL + Redis + Kafka + Elasticsearch + Spring Security + ... 并提供详细的开发文档和配套教程。公众号后台回复 Echo 可以获取配套教程,目前尚在更新中
不想看解释的小伙伴可直接翻到文末寻找答案。
1. 用户空间和内核空间
关于内核态和用户态我们在 了解操作系统的那些事儿,从这篇文章开始 这篇文章中已经详细介绍过,这里不再过多赘述。
至于什么是系统空间和用户空间也非常好理解:在操作系统中,内存通常会被分成用户空间(User space)与内核空间(Kernel space)这两个部分。当进程/线程运行在用户空间时就处于用户态,运行在内核空间时就处于内核态:
- 运行在内核态的程序可以访问用户空间和内核空间,或者说它可以访问计算机的任何资源,不受限制,为所欲为,例如协调 CPU 资源,分配内存资源,提供稳定的环境供应用程序运行等
- 而应用程序基本都是运行在用户态的,或者说用户态就是提供应用程序运行的空间。运行在用户态的程序只能访问用户空间
那为什么要区分用户态和内核态呢?
其实早期操作系统是不区分用户态和内核态的,也就是说应用程序可以访问任意内存空间,如果程序不稳定常常会让系统崩溃,比如清除了操作系统的内存数据。为此大佬们设计出了一套规则:对于那些比较危险的操作需要切到内核态才能运行,比如 CPU、内存、设备等资源管理器程序就应该在内核态运行,否则安全性没有保证。
举个例子,对于文件系统和数据来说,文件系统数据和管理就必须放在内核态,但是用户的数据和管理可以放在用户态。
用户态的程序不能随意操作内核地址空间,这样有效地防止了操作系统程序受到应用程序的侵害。
那如果处于用户态的程序想要访问内核空间的话怎么办呢?就需要进行系统调用从用户态切换到内核态。
2. 操作系统线程
① 在用户空间中实现线程
在早期的操作系统中,所有的线程都是在用户空间下实现的,操作系统只能看到线程所属的进程,而不能看到线程。
从我们开发者的角度来理解用户级线程就是说:在这种模型下,我们需要自己定义线程的数据结构、创建、销毁、调度和维护等,这些线程运行在操作系统的某个进程内,然后操作系统直接对进程进行调度。
这种方式的好处一目了然,首先第一点,就是即使操作系统原生不支持线程,我们也可以通过库函数来支持线程;第二点,线程的调度只发生在用户态,避免了操作系统从内核态到用户态的转换开销。
当然缺点也很明显:由于操作系统看不见线程,不知道线程的存在,而 CPU 的时间片切换是以进程为维度的,所以如果进程中某个线程进行了耗时比较长的操作,那么由于用户空间中没有时钟中断机制,就会导致此进程中的其它线程因为得不到 CPU 资源而长时间的持续等待;另外,如果某个线程进行系统调用时比如缺页中断而导致了线程阻塞,此时操作系统也会阻塞住整个进程,即使这个进程中其它线程还在工作。
② 在内核空间中实现线程
所谓内核级线程就是运行在内核空间的线程, 直接由内核负责,只能由内核来完成线程的调度。
几乎所有的现代操作系统,包括 Windows、Linux、Mac OS X 和 Solaris 等,都支持内核线程。
每个内核线程可以视为内核的一个分身,这样操作系统就有能力同时处理多件事情,支持多线程的内核就叫做多线程内核(Multi-Threads Kernel)。
从我们开发者的角度来理解内核级线程就是说:我们可以直接使用操作系统中已经内置好的线程,线程的创建、销毁、调度和维护等,都是直接由操作系统的内核来实现,我们只需要使用系统调用就好了,不需要像用户级线程那样自己设计线程调度等。
上图画的是 1:1 的线程模型,所谓线程模型,也就是用户线程和内核线程之间的关联方式,线程模型当然不止 1:1 这一种,下面我们来详细解释以下这三种多线程模型:
下文翻译自 https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/4_Threads.html
1)多对一线程模型:
- 在多对一模型中,多个用户级线程映射到某一个内核线程上
- 线程管理由用户空间中的线程库处理,这非常有效
- 但是,如果进行了阻塞系统调用,那么即使其他用户线程能够继续,整个进程也会阻塞
- 由于单个内核线程只能在单个 CPU 上运行,因此多对一模型不允许在多个 CPU 之间拆分单个进程
从并发性角度来总结下,虽然多对一模型允许开发人员创建任意多的用户线程,但是由于内核只能一次调度一个线程,所以并未增加并发性。现在已经几乎没有操作系统来使用这个模型了,因为它无法利用多个处理核。
2)一对一线程模型:
- 一对一模型克服了多对一模型的问题
- 一对一模型创建一个单独的内核线程来处理每个用户线程
- 但是,管理一对一模型的开销更大,涉及更多开销和减慢系统速度
- 此模型的大多数实现都限制了可以创建的线程数
从并发性角度来总结下,虽然一对一模型提供了更大的并发性,但是开发人员应注意不要在应用程序内创建太多线程(有时系统可能会限制创建线程的数量),因为管理一对一模型的开销更大。Windows (从 Win95 开始) 和 Linux 都实现了线程的一对一模型。
3)多对多线程模型:
- 多对多模型将任意数量的用户线程复用到相同或更少数量的内核线程上,结合了一对一和多对一模型的最佳特性
- 用户对创建的线程数没有限制
- 阻止内核系统调用不会阻止整个进程
- 进程可以分布在多个处理器上
- 可以为各个进程分配可变数量的内核线程,具体取决于存在的 CPU 数量和其他因素
3. Java 线程
在进入 Java 线程主题之前,有必要讲解一下线程库 Thread library 的概念。
在上面的模型介绍中,我们提到了通过线程库来创建、管理线程,那么什么是线程库呢?
线程库就是为开发人员提供创建和管理线程的一套 API。
当然,线程库不仅可以在用户空间中实现,还可以在内核空间中实现。前者涉及仅在用户空间内实现的 API 函数,没有内核支持。后者涉及系统调用,也就是说调用库中的一个 API 函数将会导致对内核的系统调用,并且需要具有线程库支持的内核。
下面简单介绍下三个主要的线程库:
1)POSIX Pthreads:可以作为用户或内核库提供,作为 POSIX 标准的扩展
2)Win32 线程:用于 Window 操作系统的内核级线程库
3)Java 线程:Java 线程 API 通常采用宿主系统的线程库来实现,也就是说在 Win 系统上,Java 线程 API 通常采用 Win API 来实现,在 UNIX 类系统上,采用 Pthread 来实现。
下面我们来详细讲解 Java 线程:
事实上,在 JDK 1.2 之前,Java 线程是基于称为 "绿色线程"(Green Threads)的用户级线程实现的,也就是说程序员大佬们为 JVM 开发了自己的一套线程库或者说线程管理机制。
而在 JDK 1.2 及以后,JVM 选择了更加稳定且方便使用的操作系统原生的内核级线程,通过系统调用,将线程的调度交给了操作系统内核。而对于不同的操作系统来说,它们本身的设计思路基本上是完全不一样的,因此它们各自对于线程的设计也存在种种差异,所以 JVM 中明确声明了:虚拟机中的线程状态,不反应任何操作系统中的线程状态。
也就是说,在 JDK 1.2 及之后的版本中,Java 的线程很大程度上依赖于操作系统采用什么样的线程模型,这点在不同的平台上没有办法达成一致,JVM 规范中也并未限定 Java 线程需要使用哪种线程模型来实现,可能是一对一,也可能是多对多或多对一。
总结来说,回答下文题,现今 Java 中线程的本质,其实就是操作系统中的线程,其线程库和线程模型很大程度上依赖于操作系统(宿主系统)的具体实现,比如在 Windows 中 Java 就是基于 Wind32 线程库来管理线程,且 Windows 采用的是一对一的线程模型。
References
- Operating Systems - Threads:https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/4_Threads.html
- Java 线程和操作系统线程的关系:https://blog.csdn.net/CringKong/article/details/79994511?utm_medium
关注公众号 | 飞天小牛肉,即时获取更新
- 博主东南大学硕士在读,携程 Java 后台开发暑期实习生,利用课余时间运营一个公众号『 飞天小牛肉 』,2020/12/29 日开通,专注分享计算机基础(数据结构 + 算法 + 计算机网络 + 数据库 + 操作系统 + Linux)、Java 技术栈等相关原创技术好文。本公众号的目的就是让大家可以快速掌握重点知识,有的放矢。希望大家多多支持哦,和小牛肉一起成长
- 并推荐个人维护的开源教程类项目: CS-Wiki(Gitee 推荐项目,现已累计 1.6k+ star), 致力打造完善的后端知识体系,在技术的路上少走弯路,欢迎各位小伙伴前来交流学习 ~
- 如果各位小伙伴春招秋招没有拿得出手的项目的话,可以参考我写的一个项目「开源社区系统 Echo」Gitee 官方推荐项目,目前已累计 700+ star,基于 SpringBoot + MyBatis + MySQL + Redis + Kafka + Elasticsearch + Spring Security + ... 并提供详细的开发文档和配套教程。公众号后台回复 Echo 可以获取配套教程,目前尚在更新中。
Java 线程和操作系统的线程有啥区别?的更多相关文章
- 5、CPU 的线程与操作系统的线程有何关系?操作系统中的进程和线程是什么关系?
CPU中的线程和操作系统(OS)中的线程即不同,在调度的时候又有些关联.CPU中的线程,我们叫它们Thread,和OS中的线程的名字一样.它来自同步多线程(SMT,Simultaneous Multi ...
- java线程中的sleep和wait区别
面试题:java线程中sleep和wait的区别以及其资 ...
- Java进阶(四十三)线程与进程的区别
Java进阶(四十三)线程与进程的区别 1.线程的基本概念 概念:线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必 ...
- java线程interrupt、interrupted 、isInterrupted区别
前言 在分析interrupt之前,应该先了解java里线程有5种状态,其中有一个阻塞状态,interrupt和阻塞有关. interrupt() 方法 作用于要中断的那个线程. interrupt( ...
- -1-5 java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait(),notify(),notifyAll()等方法都定义在Object类中
本文关键词: java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait( ...
- 【java多线程】用户线程和守护线程的区别
java中线程分为两种类型:用户线程和守护线程.通过Thread.setDaemon(false)设置为用户线程:通过Thread.setDaemon(true)设置为守护线程.如果不设置次属性,默认 ...
- 《Java多线程面试题》系列-创建线程的三种方法及其区别
1. 创建线程的三种方法及其区别 1.1 继承Thread类 首先,定义Thread类的子类并重写run()方法: package com.zwwhnly.springbootaction.javab ...
- Java实现线程的三种方式和区别
Java实现线程的三种方式和区别 Java实现线程的三种方式: 继承Thread 实现Runnable接口 实现Callable接口 区别: 第一种方式继承Thread就不能继承其他类了,后面两种可以 ...
- 额!Java中用户线程和守护线程区别这么大?
在 Java 语言中线程分为两类:用户线程和守护线程,而二者之间的区别却鲜有人知,所以本文磊哥带你来看二者之间的区别,以及守护线程需要注意的一些事项. 1.默认用户线程 Java 语言中无论是线程还是 ...
随机推荐
- CentOS7集群环境Elastic配置
CentOS7集群环境Elastic配置 (首先去官网下载elasticsearch的source code并解压到/usr/soft目录下) (以下默认root账户) 1.更改配置文件 文件路径:/ ...
- Spring Cloud基础
1.网站架构演变过程 传统架构(单点应用SSM或SSH)→分布式架构(项目拆分)→SOA架构(面向服务架构)→微服务架构 2.微服务概述 2.1SOA架构 面向服务的架构(SOA)是一个组件模型,它将 ...
- OSS对象储存
简介 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量.安全.低成本.高可靠的云存储服务. 使用流程 名词解释 Endpoint(访问域名) Ac ...
- CSS实现页面切换时的滑动效果
最近在开发手机端APP页面功能时遇到一个需求:某个页面查询的数据有三种分类,需要展示在同一页面上,用户通过点击分类标签来查看不同类型的数据, 期望效果是 用户点击标签切换时另一个页面能够以一个平滑切入 ...
- kubernetes cpu限制参数说明
docker CPU限制参数 Option Description --cpus=<value> Specify how much of the available CPU resourc ...
- threejs 基础概要
threejs 基础概要 点击查看官方文档 下面是翻译的内容(稍作修改) 先了解一下Three.js应用程序的结构.Three.js应用程序需要创建一堆对象并将它们连接在一起.下图表示一个小three ...
- 使用当前主流的github管理项目代码(记我的第一次项目创建)
先创建一个github的账号 网址:https://github.com/ 然后下载一个git工具并安装 网址:https://gitforwindows.org/ 下载安装注册完成后, 创建一个新的 ...
- Spring中各种扩展原理及容器创建原理
一.BeanFactoryPostProcessor BeanFactory的后置处理器:在BeanFactory标准初始化之后调用,来定制和修改BeanFactory的内容:所有的bean定义已经保 ...
- 第三方API接口测试问题反馈文档
大家在给甲方做大型项目的时候,有时候参与的厂商比较多,而公司负责的部分又需要第三方厂商提供接口支持. 例如我们做医疗行业的,给医院提供医保控费系统服务的,就需要HIS厂商提供接口给我们采集数据.有时候 ...
- WS1008网络损伤测试仪
WS1008网络损伤测试仪具备高性能的网络损伤仿真功能.冗余链路测试功能和线速流量生成功能,提供了综合性的网络系统测试方案,可充分测试.验证网络系统的抗损伤能力.链路切换能力及数据转发能力.为高可靠性 ...