线程基础

线程基础

Scroll Down

线程模型

在Java中,代表线程的Thread类中大多方法都是由与平台相关的Native方法实现的,由于各类操作系统中线程模型不同,所以Java线程模型的实现也必然有差别,事实上,JVM规范中也并未规定Java中线程需要使用哪种模型来实现,完全依赖于虚拟机的具体实现。

在Windows版和Linux版的Sun JDK中,Java线程是用一对一的线程模型实现的,在一对一线程模型中,内核通过线程调度器调度内核线程,内核线程通过暴露轻量级进程给进程调用实现线程,这里的轻量级进程,就是我们通常意义上所讲的线程,具体关系图如下图所示: image.png

状态

Java语言定义了以下几种线程状态

  • New(创建后还未启动)
  • Runable(就绪及运行中)
  • Waiting(无限期等待,一般未设置timeout的wait和join还有LockSupport.park会进入此状态)
  • Timed Waiting(有限期等待,时间到了会被系统唤醒)
  • Blocked (阻塞状态,等待的是获取一个排它锁,而不像Waiting是等待一个唤醒动作)
  • Terminated(终止状态,线程执行结束)

中断与唤醒

在Java中,Waiting状态和Timed Waiting状态的线程可以被interrupt方法中断,但具体的中断操作并不是由interrupt方法实现,事实上,调用interrupt后所做的仅仅只是将被中断线程interrupt标志位置为true,而在Waiting状态和Timed Waiting状态下的线程是不占用CPU的,因此也无法给interrupt标志置位,此时就会抛出InterruptException,线程为了处理异常则会从等待状态重新变回运行状态,有了以上逻辑,我们也能知道,Java的中断并不是字面意义上粗暴的将线程停止或唤醒,而仅仅只是变化线程的interrupt标志位,具体的中断操作还是需要该线程中的具体业务逻辑实现,占用CPU的线程在被interrupt后只会改变interrupt标志位,而不占用CPU的线程则会在等待处抛出一个InterruptException异常

用户态与内核态切换

如上述所说,在Java中,内核线程与Java线程是1:1的关系,而在操作系统中(以Linux为例),内核线程的调度是无法在用户态完成的,因此当Java进程需要调度线程时,必须陷入内核态,而从用户态切换到内核态,就会产生额外的开销。

产生开销的点主要在于,在从用户态进入内核态前,需要保存用户程序的上下文,记录用户态的寄存器位置,在内核态切回用户态前,需要恢复用户态寄存器的内容