Java并发04:图解线程生命周期

73 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

学习MOOC视频记录的笔记

线程的一生——6个状态(生命周期)

1.有哪6种状态?

  • New
  • Runnable
  • Blocked
  • Waiting
  • Timed Waiting
  • Terminated

2.每个状态是什么含义?

状态含义
New已创建但还没启动的新线程,也就是创建了一个线程但是还没有执行 start 方法时候的状态,即做了一些准备工作,但是还没有执行 run 方法里面的代码
Runnable可运行的,只要调用了 start 就进入这个状态,对应着操作系统中的两种状态,分别是 ReadyRunning 即可以是可运行的,又可以是实际运行中的。如果一个正在运行的线程的 CPU 资源被抢走了,对应的状态还是 Runnable
Blocked当一个线程进入被 synchronized 修饰的代码块的时候,如果该锁已经被其他的线程拿走了,这个线程就进入了 Blocked 状态;注意一定是 synchronized 修饰的部分
Waiting等待,没有设置 timeout 参数的 Object 中的 wait 方法
Timed Waiting计时等待,超时的时候会被自动唤醒,也可以由唤醒信号提前唤醒
Terminated终止状态,执行完成。情况1:①程序正常执行退出;②出现了一个异常

3.状态间的转化图示

image-20210301160545727

image-20221105143013771

状态转化的特殊情况

  • Object.wait 状态刚被唤醒时,通常不能立刻抢到 monitor 锁,那就会从 Waiting先进入Blocked 状态 ,抢到锁后再转换到 Runnable 状态(官方文档)
  • 如果发生异常,可以直接跳到终止 Terminated 状态,不必再遵循路径,比如可以从Waiting 直接到 Terminated
 /**
 * 展示线程的NEW、RUNNABLE、Terminated状态。
 * 即使是正在运行,也是Runnable状态而不是Running
 */
 public class NewRunnableTerminated implements Runnable {
  
     public static void main(String[] args) {
         Thread thread = new Thread(new NewRunnableTerminated());
         // 打印出NEW的状态
         System.out.println(thread.getState());
         thread.start();
         System.out.println(thread.getState());
         try {
             Thread.sleep(10);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         // 打印出RUNNABLE的状态,即使是正在运行,也是RUNNABLE,而不是RUNNING
         System.out.println(thread.getState());
  
         try {
             Thread.sleep(100);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         // 打印出TERMINATED的状态
         System.out.println(thread.getState());
     }
  
     @Override
     public void run() {
         for (int i = 0; i < 1000; i++) {
             System.out.println(i);
         }
     }
 }

部分运行结果如下:

image-20210301161722410

 /**
 * 展示Blocked,Waiting,TimedWaiting
 */
 public class BlockedWaitingTimedWaiting implements Runnable {
  
     public static void main(String[] args) {
         BlockedWaitingTimedWaiting runnable = new BlockedWaitingTimedWaiting();
         Thread thread1 = new Thread(runnable);
         thread1.start();
         Thread thread2 = new Thread(runnable);
         thread2.start();
         // 避免主线程运行过快输出两个RUNNABLE状态的情况
         try {
             Thread.sleep(50);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         // 打印出TIMED_WAITING状态,因为正在执行Thread.sleep(1000);
         System.out.println(thread1.getState());
         // 打印出BLOCKED状态,因为thread2想拿到sync()的锁却拿不到
         System.out.println(thread2.getState());
         try {
             Thread.sleep(1300);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         // 打印出WAITING状态
         System.out.println(thread1.getState());
     }
  
     @Override
     public void run() {
         syn();
     }
  
     /**
      * 第一个线程进来获得锁,并sleep(1000),进入TimedWaiting状态
      * 此时第二个线程无法获取锁,进入Blocked状态
      */
     private synchronized void syn() {
         try {
             Thread.sleep(1000);
             wait();
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
     }
 }

程序运行结果:

 TIMED_WAITING
 BLOCKED
 WAITING
  • 有一些状态是没有回头路的,左侧三个是从上往下的。
  • 状态之间是不能跳跃的。

4.阻塞状态是什么?

一般习惯而言,把 Blocked(被阻塞)、Waiting(等待)、Timed_waiting(计时等待)都称为阻塞状态,都是使线程陷入一种阻塞的状态。不仅仅是 Blocked

被阻塞的情况下什么时候被唤醒能继续运行是不受到我的控制的,比如等待 synchronized 锁,有可能永远无法获得锁,陷入死锁的情况。

5.常见面试问题

线程有哪几种状态?生命周期是什么?

见上图