Java Thread基础(3)
线程的实现
线程的实现主要有3种方式:
- 使用内核线程实现;
- 使用用户线程实现
- 使用用户线程加轻量级进程混合实现。
内核线程就是直接由操作系统内核支持的线程,这类线程由内核来完成线程切换,内核通过调度器调度线程,并将线程的任务映射到各个处理器上。
轻量级进程是内核线程的一种高级接口——轻量级进程,轻量级进程就是通常意义上所说的线程,每个轻量级进程都由一个内核线程支持,这种轻量级进程与内核进程之间1:1的关系称为一对一线程模型。每个轻量级进程都是一个独立的调度单元,即使有一个轻量级进程在系统调用中被阻塞了,也不会影响整个进程。
轻量级进程有它的局限性:
- 基于内核线程实现,所以各种线程操作,如创建,析构和同步,都需要进行系统调用,这需要在用户态和内核态之间来回切换,代价较高。
- 每个轻量级进程都需要一个内核线程的支持,需要消耗一定的内核资源。因此,一个系统支持的轻量级进程的数量是有限的。
用户线程的广义定义是:一个线程只要不是内核线程,就可以认为是用户线程。所以,广义地说,轻量级进程也是用户线程。但是,轻量级进程的实现始终是建立在内核上的。
用户线程的狭义定义是指完全建立在用户空间上的线程库,系统内核不能感知线程存在的实现。用户线程的建立、同步、销毁和调度完全在用户态中完成,不需要内核的帮助。这种线程快速高效,常用于实现进程与线程的1:N关系。
用户线程的劣势在于没有内核的支持,所有的线程操作都需要自己实现,程序一般比较复杂。
用户线程加轻量级进程混合实现:将轻量级进程作为用户线程和内核线程之间的桥梁。
主流的操作系统都提供了线程实现,java 语言则提供了在不同硬件和操作系统平台下对线程操作的统一处理。每个执行了start()
方法并且还未结束的Thread实例,都代表一个线程。Thread类中的关键方法大都是声明为Native(平台相关)的。
线程调度
线程调度的主要方式有2种:协同式线程调度和抢占式线程调度。
使用协同式线程调度的多线程系统,线程的执行时间由线程自身来控制,线程完成自身任务后,要主动通知系统切换到另外一个线程上。协同式系统的最大好处在于实现简单,且不存在线程同步问题。同样,坏处也很明显,如果一个线程有问题,一直不告知系统切换就会一直阻塞在那。使用抢占式调度的系统,线程由系统来分配时间,线程的切换不受自身控制。在这种情况下,不存在线程导致整个进程阻塞的情况,Java线程的调度方式就是抢占式调度。
线程的生命周期
Java 在枚举类Thread.State
中定义了线程的几种状态:
- NEW
新建状态:线程刚刚创建,尚未启动。 - RUNNABLE
就绪状态:线程可执行,等待获取CPU使用权。 - BLOCKED
阻塞状态:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。 - WAITING
等待状态:运行的线程执行wait()
,join()
或LockSupport.park()
方法,JVM会把该线程放入等待池中。当前线程在等待另一线程的特定动作。 - TIMED_WAITING
限时等待状态:运行的线程执行带时间参数wait()
,带时间参数join()
,sleep()
,LockSupport.parkNanos()
或LockSupport.parkUntil()
方法,JVM会把该线程放入等待池中。当前线程在等待另一线程的特定动作。 - TERMINATED
死亡状态:线程执行完成或者因异常退出,结束生命周期。