【Java 并发编程系列3】线程状态 & 守护线程


一、线程状态说明

Java 的线程在运行阶段会有不一样的状态,在Java代码中表现为一个枚举类 Thread.State 其定义以下:
前端

public enum State {
 // 还没有启动的线程状态,通常是建立好的线程还没有调用start() 方法局处于NEW状态
 NEW,
       
 // 线程处于可运行的状态,表示能够被JVM执行,可是也可能处于等待其余资源的状态,例如等待处理器的资源
 // JVM 概述的将可运行与运行中,统称为RUNABLE   
 RUNNABLE,
       
 // 线程处于阻塞状态,表示线程正在等待获取锁,通常是synchronized代码或者调用某个对象wait()方法
 // 暂时获取不到锁,处于其余资源释放锁的等待状态
 BLOCKED,
       
 /**
  * 线程状态处于等待状态,多是调用如下的方法:
  *   <li>{@link Object#wait() Object.wait}</li>
  *   <li>{@link #join() Thread.join} with no timeout</li>
  *   <li>{@link LockSupport#park() LockSupport.park}</li>
  *
  * 或者是处于等待状态的线程在等待其余线程执行特定的动做,好比当前线程调用了某个对象的Object.wait()方法 
  * 该线程将会等待其余线程调用该对象的Object.notify()方法或者Object.notifyAll()方法
  * 或者调用了Thread.join()方法的线程等待其余线程的完成,即等待其余线程进入TERMINATED状态
  */
 WAITING,
       
 /**
  * 线程处于有限时间的等待,通常是调用的了包含时间的等待放方法,好比下面的方法
    {@link #sleep Thread.sleep} 休眠了必定的时间
    {@link Object#wait(long) Object.wait}
    {@link #join(long) Thread.join} with timeout
    {@link LockSupport#parkNanos LockSupport.parkNanos}
    {@link LockSupport#parkUntil LockSupport.parkUntil}
  */
 TIMED_WAITING,
       
 /**
  * 线程处于消亡状态,表示线程已经执行完成。
  */
 TERMINATED;

二、线程状态的切换流程


经过上文的枚举状态说明,咱们了解到Java程序运行的代码状态的具体含义,线程在自身切换的生命周期中,并非固定处于某个状态,而是随着代码的执行在不停地切换,下图概述了Java线程的状态切换流程。
java

在这里插入图片描述

  • 建立新的线程,在调用start()方法以前状态为 NEW
  • 调用start()方法,线程由 NEW 进入 RUNNABLE 状态,JVM笼统的将正在运行和等待CPU执行统称为 RUNNABLE
  • 若是调用 Object.wait() 或者LockSupport.park() 方法则进入WAITING状态,当其余线程调用Object.notify()或者Obeject.notifyAll() 方法时候,线程可能会恢复为 RUNABLE , 若是设置等待超时参数,则会进入 TIMED_WAITING 状态
好比多个线程都在等待某个对象的notify()方法或者notifyAll()被调用,在恢复的时候可能就是随机选择一个等待该对象nofify()的线程恢复,其余线程继续等待,因此此处才声明有可能恢复为RUNABLE状态
  • 调用 Thread.join() 方法也会进入WAITING或者TIMED_WAITING状态,只有在对应的线程消亡后,才会跳出 WAITING 或者TIMED_WAITING 状态


  • 当程序进入同步方法或者同步代码块的时候,即进入 synchronized 关键字修饰的方法或者代码块的时候,则进入阻塞状态
通常其余的Lock同步的话,则会进入WAITING或则TIMED_WAITING 状态,而非 BLOCKED 状态
  • 程序执行完成后进入 TERINATED 状态

三、守护线程

顾名思义,守护线程就是守护其余线程的执行,当进程没有非守护进程的时候,JVM就会退出 (只有进程中存在非守护线程,VM才不会退出)。它主要用于在程序后台进行调度以及其余支持。能够经过 Thread.setDaemon(bool) 来设置当前线程是是守护线程(传参true)仍是用户线程(传参false)。该设置仅在Thread处于NEW状态时候设置有效,不能在线程启动以后设置。若是设置则会抛出异常 IllegalThreadStateException
算法

public final void setDaemon(boolean on) {
    checkAccess();
    if (isAlive()) {
        throw new IllegalThreadStateException();
    }
    daemon = on;
}

/**
 * Tests if this thread is alive. A thread is alive if it has
 * been started and has not yet died.
 */
public final native boolean isAlive();

当JVM退出的时候,守护线程并不必定会执行完毕,好比并不会执行finally方法,因此咱们并不能依赖守护线程的finally方法来进行资源的关闭或者释放。好比下面的代码
编程

public class DaemonThread implements Runnable {
  @Override
  public void run() {
    try {
      SleepUtils.sleep(2);
    } finally {
      // 此代码并不会被执行
      System.out.println("DaemonThread.run.finally");
    }
  }

  public static void main(String[] args) {
    Thread thread = new Thread(new DaemonThread(), "DaemonThread");
    thread.setDaemon(true);
    thread.start();
  }
}


在上一篇文章线程的建立,展现了一段线程建立的init() 方法的代码,里面的代码展现了线程的是不是守护线程会被继承到其建立的线程的,也就是说守护线程建立的线程,默认也是守护线程后端

this.daemon = parent.isDaemon();
相关文章
相关标签/搜索