线程的实现

Thread类的所有关键方法都是声明为Native的,在JavaAPI中一个Native方法往往意味着这个方法没有使用或者无法使用平台无关的方法来实现。

实现线程主要又三种方式:内核线程实现,使用用户线程实现,和使用用户线程加轻量级进程混合实现。

1.使用内核线程实现

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

程序一般不会直接去使用内核线程,而是去使用内核线程的一种高级接口——轻量级进程,轻量级进程就是我们通常意义上的线程,与内核线程是 1:1 的关系。如图所示

default

由于内核线程的支持,每个轻量级进程都成为一个独立的调度单元,即使有一个轻量级进程在系统调用中阻塞了,也不会影响整个进程继续工作。

局限性:

a.基于内核线程实现,各种线程操作如 创建、析构及同步都需要进行系统调用。但是系统调用代价相对较高,需要再用户态和内核态中来回切换

b.轻量级进程要消耗一定的内核资源,因此数量有限。

2.使用用户线程实现

狭义上的用户线程是指完全建立在用户空间的线程库上,系统内核不能感知线程存在的实现。用户线程的建立、同步、销毁、调度都在用户态中完成,不需要内核的帮助。

因此操作是非常快速且低消耗的,也可以支持规模更大的线程数量。这种进程与线程之间是 1:N的关系。如图

default

局限性:由于没有系统内核的支持,所有线程操作都需要用户程序自己处理,这种方法使用较少了。

3.用户线程 + 轻量级进程

在这种情况下,既存在用户线程又存在内核线程,用户线程的创建、切换、析构操作依然低耗,同时可以支持大规模的用户线程并发,而轻量级进程可以提供线程调度功能和处理器映射。如图
default

线程调度

主要调度方式有两种:协同式调度和强占式调度。

  • 协同式调度:线程把自己的工作执行完了之后,主动通知系统切换到另一个线程上。最大好处就是实现简单,切换操作对于线程是可知的,所以不需要考虑同步问题。缺点就是如果一个线程编写有问题,一直不告知系统进行线程切换,那么程序就会一直阻塞在哪里。
  • 强占式调度:每个线程将由系统来分配执行时间,线程的切换不由线程本身来决定,在这种线程实现的方式下,线程的执行时间是系统可控的,不会有一个线程导致整个进程阻塞的问题。这也是Java使用的线程调度方式。

如果希望系统对于某些线程可以“偏袒”一点,则可以通过设置优先级来实现。但优先级每个平台可能不一样,所以最好是设立三个优先级,来实现可移植性。

状态转换
default