前言
 
我们知道,线程是 CPU 独立调度的单位,通过引入线程,实现时分复用,利用并发思想使得我们的程序运行的更加迅速。

主流的操作系统都提供了线程的实现,注意这句话,谁实现的线程?是操作系统,尽管本文侧重于介绍 Java 线程的实现原理,但是请大家清楚一点,实际上实现线程的老大哥,是运行在内核态的操作系统。

Java 语言提供了不同硬件和操作系统平台下对线程操作的统一处理,每个已经执行 start() 且还未结束的 java.lang.Thread 类的实例就代表了一个线程。但是正如我们刚刚所强调的那样,线程可是由操作系统来实现的啊,那么 Java 是如何面向开发者提供的线程统一操作呢?我们来简单的看一下 Thread 类的几个关键方法。

private static native void registerNatives();
    
    public static native Thread currentThread();

    public static native void yield();
    
    public static native void sleep(long millis) throws InterruptedException;

    public final native boolean isAlive();

有没有发现一个比较特殊的共同点?对,这些方法都是被 native 关键字所修饰的,你在阅读这些方法的源码的时候看不见这些方法具体实现的 Java 代码。因为在 Java 的 API 中,一个 native 方法往往意味着这个方法无法使用平台无关的手段来实现。所以,还是那句话,实际上线程的实现与 Java 无关,由平台所决定,Java 所做的是将 Thread 对象映射到操作系统所提供的线程上面去,对外提供统一的操作接口,向程序员隐藏了底层的细节,使程序员感觉在哪个平台上编写的有关于线程的代码都是一样的。这也是 Java 这门语言诞生之初的核心思想,一处编译,到处运行,只面向虚拟机,实现所谓的平台无关性,而这个平台无关性就是由虚拟机为我们提供的。

操作系统实现线程主要有 3 种方式

  • 用户级线程
  • 内核级线程
  • 用户级线程 + 内核级线程,混合实现

下面简单的介绍一下前两种基础的线程模型.

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

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

java 用户级线程 java线程底层实现_内核线程


由于有内核线程的支持,每个轻量级进程都成为一个独立的调度单元,即使有一个轻量级进程在系统调用中阻塞了,也不会影响整个进程继续工作,但是轻量级进程具有它局限性,主要有如下两点

  • 线程的创建、销毁等操作,都需要进行系统调用,而系统调用的代价相对较高,需要在用户态和内核态之间来回切换。
  • 每个轻量级进程都需要有一个内核线程的支持,因此轻量级进程要消耗一定的内核资源(比如内核线程的栈空间),因此一个系统支持轻量级线程的数量是有限的。

 
用户线程
 
从广义上讲,一个线程只要不是内核线程,就可以认为是用户线程。从狭义上讲,用户线程指的是完全建立在用户空间的线程库上,系统内核不能感知线程存在的实现。用户线程的建立、同步、销毁和调度完全在用户态中完成,不需要内核的帮助。如果程序实现得当,这种线程不需要切换到内核态,因此操作可以是非常快速且低消耗的,并且可以支持规模更大的线程数量。这种进程与用户线程之间 1 : N 的关系称为一对多的线程模型,如下图所示。

java 用户级线程 java线程底层实现_内核线程_02

使用用户线程的优势在于不需要内核支援,劣势也在于没有内核的支援,所有的线程操作都需要用户程序自己处理。线程的创建、切换和调度都是需要考虑的问题。因而使用用户线程实现的程序都比较复杂,除了以前在不支持多线程的操作系统中的多线程程序与少数有特殊需求的程序外,现在使用用户线程的程序越来越少了。

下面这篇文章是我的另一篇文章,这篇文章是我学习操作系统时整理的笔记,对于这两种线程模型的实现介绍的更加详细。

线程模型:用户级线程与内核级线程介绍与对比

 
Java 线程的实现
 

Java 线程在 JDK1.2之前,是基于称为“绿色线程”的用户线程实现的,而在 JDK 1.2 中,线程模型替换为基于操作系统原生线程模型来实现,因此,在目前的 JDK 版本中,操作系统支持怎样的线程模型,在很大程度上决定了 Java 虚拟机的线程是怎样映射的,这点在不同平台上没有办法达成一致,虚拟机规范中也并未限定 Java 线程需要使用哪种线程模型来实现。

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