【Java多线程】Java线程状态及转换方法详解


在学习Java多线程时,总是被这么多种状态以及其转换方法搞得很头大,今天这篇文章就来捋一捋Java多线程中的几种线程状态以及相应的转换方法!

在讲解Java线程状态前先来看看在现代操作系统中更加主流的线程状态和转换:

1. 现代操作系统中的线程状态及转换(5种)

在现在的操作系统中,线程是被视为轻量级进程的,所以操作系统线程的状态其实和操作系统进程的状态是一致的。具有以下 5 种状态:

操作系统的线程状态转换图

  • 创建态(new) :进程正在被创建,尚未到就绪状态。
  • 就绪态(ready) :进程已处于准备运行状态(等待被调度),即进程获得了除了处理器之外的一切所需资源,一旦得到处理器资源(处理器分配的时间片)即可运行。
  • 运行态(running) :进程正在处理器上上运行(单核 CPU 下任意时刻只有一个进程处于运行状态)。
  • 阻塞态(waiting) :又称为等待状态(等待资源),进程正在等待某一事件而暂停运行如等待某资源为可用或等待 IO 操作完成。即使处理器空闲,该进程也不能运行。
  • 结束/终止态(terminated) :进程正在从系统中消失。可能是进程正常结束或其他原因中断退出运行。

状态转换条件:

  • 就绪态→运行态:处于就绪态的进程被调度后,获得处理机资源(分派处理机时间片),于是进程由就绪态转换为运行态。
  • 运行态→就绪态:处于运行态的进程在时间片用完后,不得不让出处理机,从而进程由运行态转换为就绪态。此外,在可剥夺的操作系统中,当有更高优先级的进程就绪时,调度程序将正在执行的进程转换为就绪态,让更高优先级的进程执行。
  • 运行态→阻塞态:进程请求某一资源(如外设)的使用和分配或等待某一事件的发生(如 I/O 操作的完成)时,它就从运行态转换为阻塞态。进程以系统调用的形式请求操作系统提供服务,这是一种由运行用户态程序调用操作系统内核过程的形式。
  • 阻塞态→就绪态:进程等待事件到来时,如 I/O 操作结束或中断结束时,中断处理程序必须把相应进程的状态由阻塞态转换为就绪态。

应该注意以下内容:

  • 只有就绪态和运行态可以相互转换,其它的都是单向转换。就绪状态的进程通过调度算法从而获得 CPU 时间片,转为运行状态;而运行状态的进程,在分配给它的 CPU 时间片用完之后就会转为就绪状态,等待下一次调度。
  • 阻塞状态是缺少需要的资源从而由运行状态转换而来,但是该资源不包括 CPU 时间,缺少 CPU 时间会从运行态转换为就绪态。

2. Java 线程状态(6种)

// Thread.State 源码
public enum State {
   
    NEW,
    RUNNABLE,
    BLOCKED,
    WAITING,
    TIMED_WAITING,
    TERMINATED;
}
2.1 NEW 创建

处于 NEW 状态的线程此时尚未启动。这里的尚未启动指的是还没调用 Thread 实例的 start() 方法

private void testStateNew() {
   
    Thread thread = new Thread(() -> {
   });
    System.out.println(thread.getState()); // 输出 NEW 
}

从上面可以看出,只是创建了线程而并没有调用 start() 方法,此时线程处于 NEW 状态。

关于 start() 的两个引申问题:

  1. 反复调用同一个线程的 start() 方法是否可行?
  2. 假如一个线程执行完毕(此时处于 TERMINATED 状态),再次调用这个线程的 start() 方法是否可行?

要分析这两个问题,先来看看 start() 的源码:

public synchronized void start() {
   
    if (threadStatus != 0)
        throw new IllegalThreadStateException();

    group.add(this);

    boolean started = false;
    try {
   
        start0();
        started = true;
    } finally {
   
        try {
   
            if (!started) {
   
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
   

        }
    }
}

可以看到,在 start() 内部,这里有一个 threadStatus 的变量。如果它不等于 0,调用 start() 是会直接抛出异常的。

接着往下看,有一个 native 的 start0() 方法。这个方法里并没有对 threadStatus 的处理。可以通过 debug 的方式再看一下:

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kaho Wang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值