Java线程&OS线程

287 阅读3分钟

OS 线程状态

  • NEW(新建):创建状态,当调用new Thread(runnable)后创建一个线程。
  • RUNNABLE(就绪):就绪状态,当线程调用了start启动线程后,线程进入就绪状态,此时它随时会被CPU调度启用。
  • RUNNING(运行):运行状态,线程被CPU调度执行的过程。
  • BLOCKED(阻塞):阻塞状态,当线程调用sleep或者wait方法或者线程等待获取被其他线程持有的锁的时候,被称为阻塞状态,当线程获得了锁或者被唤醒等将再次进入运行状态。
  • TERMINATED(终止):终止状态,当线程任务执行完成了或者被强行终止了,就进入终止状态,并且线程进入了终止状态后无法再恢复到其它状态。

Java#Thread线程状态

今天看Thread源码,发现Thread内部有public枚举State,描述了Thread在应用层面的几种线程状态,根据源码注释知道了它和操作系统线程状态略有差异。

 
 public enum State {
     NEW,// 创建状态
     RUNNABLE,// 运行状态
     BLOCKED,// 阻塞状态
     WAITING,// 等待状态
     TIMED_WAITING,// 有时限的等待状态
     TERMINATED;// 终止状态
 }
 ​
 ​

可以看到Java的Api Thread的状态比操作系统的线程状态多一个状态,并且没有就绪状态;java线程操作系统的RUNNABLE和RUNNING统一归类到RUNNABLE状态,将阻塞等待分为了三个,分别是BLOCKED、WAITING、TIME_WAITING状态。

Java和OS线程状态对应关系

image-20220427204608636-16510635712591.png

状态演示

NEW

线程创建状态,当Java里面调用了new Thread(),在构造方法里面会调用init方法,进行各种初始化操作,包括分配ThreadID,获取ClassLoader等操作,在这里就创建了 一个线程。

 Thread thread = new Thread(() -> {
     System.out.println("");
 });
 System.out.println("线程创建:" + thread.getState());// 线程创建:NEW

RUNNABLE

因为在Java中Thread是应用层面的API,它无法直接感知到内核对线程的操作,因此将操作系统线程的RUNNABLE(就绪)和RUNNING(运行)统一归到运行状态。对Java来说,只要线程没有终止或者阻塞都属于在正常运行状态。

这一块用代码不好演示,因为一旦执行到了Thread的钩子方法run,那么这个Thread代表的线程肯定是已经是运行状态了,无法监控到就绪状态。

BLOCKED

BLOCKED

1、尝试获取被其它线程持有的锁(Java BLOCKED)

 // 创建一个线程,在一秒钟后尝试获取锁
 Thread thread = new Thread(() -> {
     try {
         TimeUnit.SECONDS.sleep(1);
     } catch (InterruptedException e) {
         e.printStackTrace();
     }
     System.out.println("尝试获取锁....");
     synchronized (lock){
         System.out.println("Thread run.....");
     }
 });
 thread.start();
 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 // 主线程持有锁,不释放,并监控控制台,如果控制台输入state,则打印创建的线程状态
 synchronized (lock){
     while(true){
         String readLine = br.readLine();
         if("state".equals(readLine)){
             System.out.println("线程创建:" + thread.getState());
         }
     }
 }

结果:

 尝试获取锁....
 state
 线程状态:BLOCKED

可以看到,当线程在等待获取锁的时候,Thread的状态是BLOCKED。

WAITING

Thread的WAITING是当线程被暂时挂起,等待唤醒的情况出现的状态

 Thread thread = new Thread(() -> {
     synchronized (lock){
         // 线程等待
         lock.wait();
         System.out.println("Thread run.....");
     }
 });
 thread.start();
 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 while(true){
     String readLine = br.readLine();
     if("state".equals(readLine)){
         System.out.println("线程创建:" + thread.getState());
     }
 }

结果:

 state
 线程状态:WAITING

TIMED_WAITING

 Thread thread = new Thread(() -> {
     // 线程超时等待
     TimeUnit.SECONDS.sleep(10000);
     System.out.println("Thread run.....");
 });
 thread.start();
 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 while (true) {
     String readLine = br.readLine();
     if ("state".equals(readLine)) {
         System.out.println("线程状态:" + thread.getState());
     }
 }

结果:

 state
 线程状态:TIMED_WAITING

TERMINATED

 Thread thread = new Thread(() -> {
     System.out.println("Thread run.....");
 });
 thread.start();
 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 while (true) {
     String readLine = br.readLine();
     if ("state".equals(readLine)) {
         System.out.println("线程状态:" + thread.getState());
     }
 }

结果:

 Thread run.....
 state
 线程状态:TERMINATED

因为线程执行得很快,因此执行完后查看线程状态已经终止了。

总结

Java中的Thread是API层面的线程,它对线程与内核交互无法感知,因此将操作系统线程的就绪运行统一归纳到了运行状态,对于Java来说只要线程没有终止和阻塞都是运行状态。

在Java中要使得线程阻塞,都必须要过JVM,比如synchronized获取锁操作,wait(),sleep(timeout)等,都是通过JVM层面实现的,对于JVM可以监控到的每次阻塞的原因和操作类型,因此Thread的阻塞分为了BLOCKEDWAITINGTIMED_WAITING