Java 线程状态及转换关系

本文详细介绍了Java线程的六种状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED,以及状态之间的转换。内容包括线程的创建、运行、阻塞、等待和结束等状态的描述,同时讨论了VisualVM线程监控中的状态对应关系。
摘要由CSDN通过智能技术生成

一、Java 线程状态

1 NEW(新建)

java.lang.Thread.State枚举中的NEW状态描述:

/**
 * Thread state for a thread which has not yet started.
 */
NEW

创建后尚未启动的线程处于这个状态。意思是这个线程没有被 start() 启动,或者说还根本不是一个真正意义上的线程,从本质上讲这只是创建了一个 Java 外壳,还没有真正的线程来运行。不代表调用了 start(),状态就立即改变,中间还有一些步骤,如果在这个启动的过程中有另一个线程来获取它的状态,其实是不确定的,要看那些中间步骤是否已经完成了

2 RUNNABLE(可运行)

java.lang.Thread.State 枚举中的 RUNNABLE 状态描述:

/**
 * Thread state for a runnable thread.  A thread in the runnable
 * state is executing in the Java virtual machine but it may
 * be waiting for other resources from the operating system
 * such as processor.
 */
RUNNABLE

RUNNABLE 状态包括了操作系统线程状态中的 RunningReady,也就是处于此状态的线程可能正在运行,也可能正在等待系统资源,如等待 CPU 为它分配时间片,如等待网络 IO 读取数据。RUNNABLE 状态也可以理解为存活着正在尝试占用 CPU 的线程(有可能这个瞬间并没有占用 CPU,但是它可能正在发送指令等待系统调度)。由于在真正的系统中,并不是开启一个线程后,CPU 就只为这一个线程服务,它必须使用许多调度算法来达到某种平衡,不过这个时候线程依然处于 RUNNABLE 状态

3 BLOCKED(阻塞)

java.lang.Thread.State 枚举中的 BLOCKED 状态描述:

/**
 * Thread state for a thread blocked waiting for a monitor lock.
 * A thread in the blocked state is waiting for a monitor lock
 * to enter a synchronized block/method or
 * reenter a synchronized block/method after calling
 * {@link Object#wait() Object.wait}.
 */
BLOCKED

BLOCKED 称为阻塞状态,或者说线程已经被挂起,它睡着了,原因通常是它在等待一个锁,当尝试进入一个 synchronized 语句块/方法时,锁已经被其它线程占有,就会被阻塞,直到另一个线程走完临界区或发生了相应锁对象的wait()操作后,它才有机会去争夺进入临界区的权利

在 Java 代码中,需要考虑 synchronized 的粒度问题,否则一个线程长时间占用锁,其它争抢锁的线程会一直阻塞,直到拥有锁的线程释放锁

处于 BLOCKED 状态的线程,即使对其调用 thread.interrupt() 也无法改变其阻塞状态,因为 interrupt() 方法只是设置线程的中断状态,即做一个标记,不能唤醒处于阻塞状态的线程

注意:ReentrantLock.lock() 操作后进入的是 WAITING 状态,其内部调用的是 LockSupport.park() 方法

4 WAITING(无限期等待)

/**
 * Thread state for a waiting thread.
 * A thread is in the waiting state due to calling one of the
 * following methods:
 * <ul>
 *   <li>{@link Object#wait() Object.wait} with no timeout</li>
 *   <li>{@link #join() Thread.join} with no timeout</li>
 *   <li>{@link LockSupport#park() LockSupport.park}</li>
 * </ul>
 *
 * <p>A thread in the waiting state is waiting for another thread to
 * perform a particular action.
 *
 * For example, a thread that has called <tt>Object.wait()</tt>
 * on an object is waiting for another thread to call
 * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
 * that object. A thread that has called <tt>Thread.join()</tt>
 * is waiting for a specified thread to terminate.
 */
WAITING

处于这种状态的线程不会被分配 CPU 执行时间,它们会一直等直到被其它线程唤醒

以下方法会让线程陷入无限期等待状态:

  • 没有设置 timeout 参数的 Object.wait()
  • 没有设置 timeout 参数的 Thread.join()
  • LockSupport.park()

LockSupport.park(Object blocker) 会挂起当前线程,参数 blocker 是用于设置当前线程的 “volatile Object parkBlocker” 成员变量

parkBlocker 是用于记录线程是被谁阻塞的,可以通过 LockSupport.getBlocker() 获取到阻塞的对象,用于监控和分析线程用的

BLOCKEDWAITING 的区别:

  • BLOCKED 状态是等待获取到一个排他锁,进入BLOCKED 状态都是被动的,离开BLOCKED 状态是因为其它线程释放了锁,而该阻塞线程得到了锁
  • WAITING 状态是在等待一段时间(timeout)或者其他线程唤醒动作的发生,进入WAITING 状态是主动的

5 TIMED_WAITING(限期等待)

/**
 * Thread state for a waiting thread with a specified waiting time.
 * A thread is in the timed waiting state due to calling one of
 * the following methods with a specified positive waiting time:
 * <ul>
 *   <li>{@link #sleep Thread.sleep}</li>
 *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
 *   <li>{@link #join(long) Thread.join} with timeout</li>
 *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
 *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
 * </ul>
 */
TIMED_WAITING

处于这种状态的线程也不会被分配 CPU 执行时间,不过无需等待被其它线程显示的唤醒,在一定时间之后它们会由系统自动的唤醒

以下方法会让线程进入TIMED_WAITING 限期等待状态:

  • Thread.sleep()
  • 设置了timeout参数的Object.wait()
  • 设置了timeout参数的Thread.join()
  • LockSupport.parkNanos()
  • LockSupport.parkUntil()

6 TERMINATED(结束)

/**
 * Thread state for a terminated thread.
 * The thread has completed execution.
 */
TERMINATED

已终止线程的线程状态,线程已经结束执行。换句话说,run() 方法执行完成,线程便处于这种状态。其实这只是 Java 语言级别的一种状态,在操作系统内部可能已经注销了相应的线程,或者将它复用给其他需要使用线程的请求

二、Java 线程状态转换图

在这里插入图片描述

三、VisualVM 线程监控线程状态与 Java 线程状态对应关系

通过 VisualVM 监控 JVM 时,可以通过线程标签页查看JVM的线程信息,VisualVM 的线程状态如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-55Hec1r9-1600098042778)(D:\work\公共服务\java\并发编程\images\677054-20170325171859830-198146769.jpg)]

通过 dump thread stack,并与 VisualVM 监控信息中的线程名称对应,找到的 VisualVM 每种线程状态的线程堆栈如下:

1 运行

"http-bio-8080-Acceptor-0" daemon prio=6 tid=0x000000000d7b4800 nid=0xa264 runnable [0x000000001197e000]
      java.lang.Thre
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值