每个已经执行了 start()
且还未结束的 java.lang.Thread
类的实例就代表了一个线程。Thread 类的所有关键方法都是声明为Native
的,在Java API中,一个Native方法往往意味着这个方法没有使用或者无法使用平台无关的手段来实现(也可能为了执行效率)。
1. 线程的实现
实现线程主要有3种方法:内核线程、用户线程、用户线程加轻量级进程混合实现。
1.1 使用内核线程实现
内核线程(Kernel-Level Thread, KLT
) 就是由操作系统内核支持的线程,内核通过操纵调度器(Scheduler
)对线程进行调度。
程序一般不会直接使用内核线程,而是去使用内核线程的一种高级接口-轻量级进程(Light Weight Process, LWP
),轻量级进程就是我们通常意义上所讲的线程。
这种轻量级进程与内核线程之间1:1的关系称为一对一的线程模型,如下图。
优点: 每个轻量级进程都成为一个独立的调度单元,即使有一个轻量级进程在系统中阻塞了,也不会影响整个进程继续工作。
缺点: 由于是基于内核线程实现的,所以各种线程操作,如创建、析构及同步,都需要进行系统调用,需要在用户态和内核态中来回切换,代价相对较高。
1.2 使用用户线程实现
用户线程(User Thread, UT
)指的是完全建立在用户空间的线程库上,系统内核不能感知线程存在的实现。
用户线程的建立、同步、销毁和调度完全在用户态中完成,不需要内核的帮助。因此操作比内核线程更快速,并可以支持更大的线程数量。
这种进程(不是轻量级进程)与用户线程之间1:N的关系称为一对多的线程模型。
1.3 使用用户线程加轻量级进程混合实现
在这种混合实现下,既存在用户线程,也存在轻量级进程。
用户线程还是完全建立在用户空间中,因此用户线程的创建、切换、析构等操作依然廉价。而操作系统提供轻量级进程则作为用户线程和内核线程之间的桥梁。这样可以使用内核提供的线程调度功能及处理器映射,用户线程调用通过轻量级线程来完成。
用户线程与轻量级进程的数量比是不定的,即为N:M的关系,这种就是多对多的线程模型。
2. Java 线程的实现
Java 线程在JDK 1.2
之前,是基于用户线程实现的,JDK 1.2
中替换为基于操作系统原生线程模型来实现。目前的JDK版本中,操作系统支持怎样的线程模型,很大程序上决定了Java虚拟机的线程是怎样映射的。
虚拟机规范中并未限定Java线程需要使用哪种线程模型来实现。
对于Sun JDK
来说,它的Windows版与Linux版都是使用一对一的线程模型实现的,一条Java线程映射到一条轻量级进程中,即内核线程的实现方式。
3. Java 线程的调度
线程调度是指系统为线程分配处理器使用权的过程。主要有协同式线程调度和抢占式线程调度两种。
如果使用协同式调度的多线程系统,线程的执行时间由线程本身来控制,线程把自己的工作执行完了之后,要主动通知系统切换到另外一个线程上。如果一个线程写得有问题,一直不告知系统进行线程切换,那么程序就会一直阻塞在那里。
如果使用抢占式调度的多线程系统,那么每个线程将由系统来分配执行时间,线程的切换不由线程本身来决定。
Java 使用的线程调度方法就是抢占式调度。