Java线程和操作系统线程的关系解读

 更新时间:2023年06月12日 14:46:49   作者:CringKong  
这篇文章主要介绍了Java线程和操作系统线程的关系解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

1.操作系统线程模型

1.1 线程实现在用户空间下

当线程在用户空间下实现时,操作系统对线程的存在一无所知,操作系统只能看到进程,而不能看到线程。所有的线程都是在用户空间实现。

在操作系统看来,每一个进程只有一个线程。过去的操作系统大部分是这种实现方式,这种方式的好处之一就是即使操作系统不支持线程,也可以通过库函数来支持线程。

我们换一种通俗的方式来讲解这段话,首先就是在这在模型下,程序员需要自己实现线程的数据结构、创建销毁和调度维护。也就相当于需要实现一个自己的线程调度内核,而同时这些线程运行在操作系统的一个进程内,最后操作系统直接对进程进行调度。

这样做有一些优点,首先就是确实在操作系统中实现了真实的多线程,其次就是线程的调度只是在用户态,减少了操作系统从内核态到用户态的切换开销。

当然缺点也很明显:

这种模式最致命的缺点也是由于操作系统不知道线程的存在,因此当一个进程中的某一个线程进行系统调用时,比如缺页中断而导致线程阻塞,此时操作系统会阻塞整个进程,即使这个进程中其它线程还在工作。

还有一个问题是假如进程中一个线程长时间不释放CPU,因为用户空间并没有时钟中断机制,会导致此进程中的其它线程得不到CPU而持续等待。

1.2 线程实现在操作系统内核中

内核线程就是直接由操作系统内核(Kernel)支持的线程,这种线程由内核来完成线程切换,内核通过操纵调度器(Scheduler)对线程进行调度,并负责将线程的任务映射到各个处理器上。

每个内核线程可以视为内核的一个分身,这样操作系统就有能力同时处理多件事情,支持多线程的内核就叫做多线程内核(Multi-Threads Kernel)。

通俗的将就是,程序员直接使用操作系统中已经实现的线程,而线程的创建、销毁、调度和维护,都是靠操作系统(准确的说是内核)来实现,程序员只需要使用系统调用,而不需要自己设计线程的调度算法和线程对CPU资源的抢占使用。

而不得提到的就是,Linux下的轻量级进程,因为Linux并不像Windows那样,真正的实现了线程的数据结构,而是直接采用了和系统中进程一样的实现方式。

目前的Linux已经基于NPTL实现了更符合POSIX标准的线程,之前我学习到的LinuxThreads早已经被替代,这里为自己的不求甚解反省。

轻量级进程(LWP)是建立在内核之上并由内核支持的用户线程,它是内核线程的高度抽象,每一个轻量级进程都与一个特定的内核线程关联。内核线程只能由内核管理并像普通进程一样被调度。

Linux中程序一般不会直接去使用内核线程,而是去使用内核线程的一种高级接口–轻量级进程,轻量级进程就是我们通常意义上所讲的线程,由于每个轻量级进程都由一个内核线程支持,因此只有先支持内核线程,才能有轻量级进程。 这种轻量级进程与内核线程之间1:1的关系称为一对一的线程模型。

这里要说明的是,一对一的线程模型是一种概念,Linux是一对一的线程模型,上面的表述太绕了,现在的Linux中线程已经的被更优雅的实现了。

PS:其实Linux中的pthread库就是调用了轻量级线程接口,来在操作系统中创建一个内核线程。

Pthread库目前也是基于NPTL实现,已经是一种符合POSIX标准的线程模型了,Linux摆脱了原来LWP的阴影。 

1.3使用用户线程加轻量级进程混合实现

在这种混合实现下,即存在用户线程,也存在轻量级进程。用户线程还是完全建立在用户空间中,因此用户线程的创建、切换、析构等操作依然廉价,并且可以支持大规模的用户线程并发。

而操作系统提供支持的轻量级进程则作为用户线程和内核线程之间的桥梁,这样可以使用内核提供的线程调度功能及处理器映射,并且用户线程的系统调用要通过轻量级进程来完成,大大降低了整个进程被完全阻塞的风险。

在这种混合模式中,用户线程与轻量级进程的数量比是不定的,即为N:M的关系:

明白了前面两种模型,就应该很好理解这种线程模型了,但实际上现在主流的操作系统已经不太常用这种线程模型了。

2019.3.26更新:

目前来说,作为异步回调以外的另一种解决方案,这种m:n的线程模型可以说大有可为,Golang的协程就是使用了这种模型,在用户态,协程能快速的切换,避免了线程调度的CPU开销问题,协程相当于线程的线程。

2.Java线程

2.1 Java线程在操作系统上本质

Java线程在JDK1.2之前,是基于称为“绿色线程”(Green Threads)的用户线程实现的,而在JDK1.2中,线程模型替换为基于操作系统原生线程模型来实现。

因此,在目前的JDK版本中,操作系统支持怎样的线程模型,在很大程度上决定了Java虚拟机的线程是怎样映射的,这点在不同的平台上没有办法达成一致,虚拟机规范中也并未限定Java线程需要使用哪种线程模型来实现。

线程模型只对线程的并发规模和操作成本产生影响,对Java程序的编码和运行过程来说,这些差异都是透明的。

也就说JDK1.2之前,

**程序员们为JVM开发了自己的一个线程调度内核,而到操作系统层面就是用户空间内的线程实现。

**而到了JDK1.2及以后,JVM选择了更加稳健且方便使用的操作系统原生的线程模型,通过系统调用,将程序的线程交给了操作系统内核进行调度

对于Sun JDK来说,它的Windows版与Linux版都是使用一对一的线程模型实现的,一条Java线程就映射到一条轻量级进程之中,因为Windows和Linux系统提供的线程模型就是一对一的。

也就是说,现在的Java中线程的本质,其实就是操作系统中的线程,Linux下是基于pthread库实现的轻量级进程,Windows下是原生的系统Win32 API提供系统调用从而实现多线程

2.2 Java中的线程

特别注意:这些线程的状态时JVM中的线程状态!不是操作系统中的线程状态。

2.2.1 操作系统中的进程(线程)状态**(区分和JVM中的线程状态)**

这里需要着重解释一点,在现在的操作系统中,因为线程依旧被视为轻量级进程,所以操作系统中线程的状态实际上和进程状态是一致的模型。

2.2.2 操作系统中线程和Java线程状态的关系:

从实际意义上来讲,操作系统中的线程除去newterminated状态,一个线程真实存在的状态,只有:

  • ready:表示线程已经被创建,正在等待系统调度分配CPU使用权。
  • running:表示线程获得了CPU使用权,正在进行运算
  • waiting:表示线程等待(或者说挂起),让出CPU资源给其他线程使用

为什么除去newterminated状态?

是因为这两种状态实际上并不存在于线程运行中,所以也没什么实际讨论的意义。

对于Java中的线程状态:

无论是Timed WaitingWaiting还是Blocked,对应的都是操作系统线程的**waiting(等待**)状态。

Runnable状态,则对应了操作系统中的readyrunning状态。

而对不同的操作系统,由于本身设计思路不一样,对于线程的设计也存在种种差异,所以JVM在设计上,就已经声明:

虚拟机中的线程状态,不反应任何操作系统线程状态

所以我上面说的那么多,只是作为理解模型,Java线程和操作系统线程,实际上同根同源,但又相差甚远。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java生成的随机数靠谱吗?多少次会重复?

    Java生成的随机数靠谱吗?多少次会重复?

    今天给大家带来的是关于Java的相关知识,文章围绕着Java生成的随机数靠不靠谱展开,文中有非常详细的介绍,需要的朋友可以参考下
    2021-06-06
  • SpringCloud Feign原理剖析

    SpringCloud Feign原理剖析

    feign是用在微服务中,各个微服务间的调用,它是通过声明式的方式来定义接口,而不用实现接口,feign让服务间的调用变得简单,不用各个服务去处理http client相关的逻辑,本文详细介绍SpringCloud Feign原理,需要的朋友可以参考下
    2023-06-06
  • 详解如何配置Spring Batch批处理失败重试机制

    详解如何配置Spring Batch批处理失败重试机制

    这篇文章主要来和大家一起探讨一下如何在Spring批处理框架中配置重试逻辑,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-06-06
  • Java将List转换为String的几种常见方式

    Java将List转换为String的几种常见方式

    在实际开发中经常遇到List转为String字符串的情况,下面这篇文章主要给大家介绍了关于Java将List转换为String的几种常见方式,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-03-03
  • jstack报错Unable to open socket file解决

    jstack报错Unable to open socket file解决

    这篇文章主要为大家介绍了jstack报错Unable to open socket file的解决方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-02-02
  • Apache Commons CLI构建命令行应用利器教程

    Apache Commons CLI构建命令行应用利器教程

    这篇文章主要为大家介绍了构建命令行应用利器Apache Commons CLI的使用教程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • Java接口过滤为null的字段方式

    Java接口过滤为null的字段方式

    大C的技术优化导致接口返回字段处理问题,业务架构解决规范性讨论,他们做或业务方做各有优缺点,建议他们做,可以保证对客户端的字段准确性,避免重复性工作
    2025-12-12
  • Java利用Spire.PDF实现将PDF文档转换为Word格式

    Java利用Spire.PDF实现将PDF文档转换为Word格式

    在日常工作和学习中,我们经常会遇到PDF文档,本文将详细介绍如何才能高效、精准地使用Java实现PDF到Word的自动化转换,感兴趣的小伙伴可以了解下
    2025-09-09
  • java实现饭店点菜系统

    java实现饭店点菜系统

    这篇文章主要为大家详细介绍了java实现饭店点菜系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • Java中的collection集合类型总结

    Java中的collection集合类型总结

    Java的集合类型都是对java.util包中Collection接口的继承,这里我们主要介绍依赖于collection的一些主分支,一起来看一下Java中的collection集合类型总结
    2016-05-05

最新评论