JAVA线程的生命周期

操作系统的线程生命周期

初始状态,可运行状态,运行状态,终止状态,休眠状态,他们之间的转化关系如图:

avator

  • 初始状态:线程被创建,但是还未分配cpu执行的状态。
  • 可运行状态:指线程可以分配cpu执行。
  • 运行状态:有cpu空闲时候分配cpu执行,当线程被分配给cpu执行时候,变为可执行状态。
  • 终止状态:线程执行完成或者异常终止。
  • 休眠状态:线程调用阻塞的api或者等待某个事件执行的时候会变为休眠状态。

jvm将由于将线程的调度交给操作系统,所以将可运行状态和运行状态和在了一起,因为jvm不关心这俩个状态的具体情况。

java线程的生命周期

NEW(初始装填)、RUNABLE(可运行/运行状态)、TERMINATED(终止状态)、BLOCK(阻塞)、WAIT(等待)、TIME_WAIT(有时限等待)

其中BLOCK、WAIT、TIME_WAIT都属于休眠关系

avator

  • NEW:当线程对象被创建出来的时候线程处于该状态,这时候还未对其分配cpu。具体方法是集成Thread类并且实现run方法,或者狗仔一个Thread对象把一个Runnable的接口实现传进去。
  • NEW–>RUNABLE:调用thread.start()方法线程变为RUNABLE状态。
  • RUNABLE–>休眠状态:java的休眠状态有三种BLOCK、WAIT、TIME_WAIT,分别是
    • RUNABLE–>BLOCK:当遇到synchronized代码块时候,如果竞争失败当前线程进入block状态。等待进入到线程又会变为RUNABLE状态,注意在java中如调用到了阻塞的api,是不会切换到block状态的,比如调用io的api,当前线程依然是RUNABLE状态这点要注意。
    • RUNABLE–>WAIT:如下3中情况会让当前线程进入到wait状态
      • object.wait(),没有时间限制的wait,需要调用object.notify()或者object.notifyAll()
      • 调用了其他线程的join(),没有时间限制的join,需要等待当前join的线程终止。
      • 调用了LockSupport.park(),没有事件限制的park,对应的方法是LockSupport.unPark()
    • RUNABLE–>TIME_WAIT:同上就是上面3种情况或者方法的有时间版本
  • RUNABLE–>TERMINATED:
    • 线程执行结束
    • stop()或者interrupt()方法

线程终止的方法

当一个线程执行一个很耗时的逻辑时候,可能会终止该线程的操作,比如并发情况下的网络超时,为了防止资源耗尽往往要终止。上面提到了stop或者interrupt方法

  • stop方法已经不建议使用了,因为会立即杀死线程,同时不会释放synchronized的锁,所以后面的线程都会阻塞。
  • interrupt方法相对来说就会“温柔”很多,它只是对线程了interrupt标记,当调用thread.interrupt()方法有俩种方式退出线程

    • 主动退出:对于一个一直执行的线程来说可以通过判断t1.isInterrupted()来判断是否该终端
    1
    2
    3
    4
    5
    final Thread t1 = new Thread(() -> {
    while(!t1.isInterrupted()){
    //do something
    }
    });
    • 异常退出:对于执行了wait sleep这种线程我们可以通过异常捕获来判断线程的终端,因为他们会抛出InterruptedException异常
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    final Thread t1 = new Thread(() -> {
    synchronized (lock) {
    try {
    lock.wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    return;
    }
    //do something

    //这时候会输出false因为interrupt会被清除
    System.out.println(t1.isInterrupted());
    }
    });

注意:当抛出InterruptedException异常后线程的interrupt标记会被清楚如果这时候在判断isInterrupted()方法就又变成了false