当前位置: 首页 > article >正文

Java线程状态详解

一、Java线程状态变迁(图片源自《Java 并发编程艺术》):

源自《Java 并发编程艺术》

二、Java线程状态定义

特别注意每个状态上面注释,说明了哪些方法可以进入当前状态。

  • NEW:调用new Thread() 后进入该状态;
  • RUNNABLE:调用Thread.start()进入该状态;其它方式详见上面图示。
  • BLOCKED:进入 synchronized,等待获取锁时,进入该状态;
  • WAITING:调用 Object.wait()Thread.joinLockSupport.park 后进入该状态;
  • TIMED_WAITING:调用Object.wait(timeout)Thread.join(timeout)Thread.sleepLockSupport.parkNanosLockSupport.parkUntil 后进入该状态;
  • TERMINATED:run()方法执行完毕,进入该状态。
	/**
	 * from java.lang.Thread.State
	 * 
	 * A thread can be in only one state at a given point in time.
     * These states are virtual machine states which do not reflect
     * any operating system thread states.
	*/
    public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * 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,

        /**
         * 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
         * Object.wait
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         *   “Object.wait” with no timeout
         *   “Thread.join” with no timeout
         *   “LockSupport.park”
         *
         * A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called “Object.wait()”
         * on an object is waiting for another thread to call
         * “Object.notify()” or “Object.notifyAll()” on
         * that object. A thread that has called “Thread.join()”
         * is waiting for a specified thread to terminate.
         */
        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:
         *   “Thread.sleep”
         *   “Object.wait” with timeout
         *   “Thread.join” with timeout
         *   “LockSupport.parkNanos”
         *   “LockSupport.parkUntil”
         */
        TIMED_WAITING,

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

三、代码实测

3.1 代码

public class ThreadStatus {
    public static void main(String[] args) {
        // 1.0 启动线程1
        final LockSupportThread lockSupportThread = new LockSupportThread();
        lockSupportThread.setName("ThreadStatus-lockSupportThread");
        lockSupportThread.start();

        // 2.0 启动线程2
        final SynchronizedSleepThread synchronizedSleepThread = new SynchronizedSleepThread();
        synchronizedSleepThread.setName("ThreadStatus-synchronizedSleepThread");
        synchronizedSleepThread.start();

        // 4.0 启动线程3、线程4
        final ReentrantLock reentrantLock = new ReentrantLock();
        final ReenterLockThread reenterLockSleepThread = new ReenterLockThread(reentrantLock);
        reenterLockSleepThread.setName("ThreadStatus-reenterLockSleepThread");
        reenterLockSleepThread.start();
        final ReenterLockThread reenterLockWaitThread = new ReenterLockThread(reentrantLock);
        reenterLockWaitThread.setName("ThreadStatus-reenterLockWaitThread");
        reenterLockWaitThread.start();
    }

    static class ReenterLockThread extends Thread{
        private Lock lock;

        public ReenterLockThread(Lock lock) {
            this.lock = lock;
        }

        @Override
        public void run() {
            lock.lock();
            try {
                try {
                    TimeUnit.HOURS.sleep(1);
                } catch (InterruptedException e) {
                    System.out.println("interrupt");
                }
            } finally {
                lock.unlock();
            }
        }
    }

    static class LockSupportThread extends Thread{
        @Override
        public void run() {
            LockSupport.park(); // 线程进入 waiting 状态
        }
    }

    static class SynchronizedSleepThread extends Thread{
        @Override
        public void run() {
            final Object lock = new Object();
            synchronized (lock) {
                // 3.0 启动线程3
                final SynchronizedBlockedThread synchronizedBlockedThread = new SynchronizedBlockedThread(lock);
                synchronizedBlockedThread.setName("ThreadStatus-synchronizedBlockedThread");
                synchronizedBlockedThread.start();

                try {
                    TimeUnit.HOURS.sleep(1); // 线程继续持有锁,进入Timed_Waiting状态。
                } catch (InterruptedException e) {
                    System.out.println("interrupt");
                }
            }
        }
    }

    static class SynchronizedBlockedThread extends Thread{
        private Object lock;

        public SynchronizedBlockedThread(Object lock) {
            this.lock = lock ;
        }

        @Override
        public void run() {
            synchronized (lock) { // 等待获取锁,线程进入Blocked状态。
                System.out.println("enter synchronized block");
            }
        }
    }
}

3.2 运行上面代码后在控制台通过jps 查看进程ID,然后用jstack 进程ID 来获取线程快照。

在这里插入图片描述

3.3、线程快照中找到我们代码中的3个线程状态,与我们在代码中注释一致,即:

LockSupport.park(); // 线程进入 waiting 状态
TimeUnit.HOURS.sleep(1); // 线程继续持有锁,进入Timed_Waiting状态
synchronized (lock) { // 等待获取锁,线程进入Blocked状态

在这里插入图片描述
特别注意:

  • 阻塞在java.concurrent包中 Lock 接口的线程状态是等待状态,因为 java.concurrent 包中 Lock 接口对于阻塞的实现均使用了 LockSupport 类中的相关方法,即:LockSupport.park() 会使线程进入WAITING状态;
  • synchronized等待获取锁时会进入BLOCKED状态。

在这里插入图片描述

`tip:`

	tid: java内的线程id
	nid: 操作系统级别线程的线程id
	prio: java内定义的线程的优先级
	os_prio:操作系统级别的优先级

四、补充

4.1、jdk源码注释中有如下内容:

4.1.1 Java线程状态操作系统中线程状态并非完全一致。
 * A thread can be in only one state at a given point in time.
 * These states are virtual machine states which do not reflect
 * any operating system thread states.
4.1.2 附:操作系统线程状态
  • New: A process that has just been created but has not yet been admitted(承认) to the pool of executable processes by the operating system.
  • Ready: A process that is prepared(准备) to execute when given the opportunity.
  • Running: The process that is currently being executed.
  • Waitting[Blocked]: A process that cannot execute until some event occurs(发生), such as the completion(完成) of an I/O operation.
  • Terminated: A process that has been released from the pool of executable processes by the operating system,
    either because it halted(停止) or because it aborted for some reason.
							  +----------<-----------+
							  |		 interrupt       |
+-----------+  			+-----------+			+---------------+        +------------+ 
|	new 	|---------> |   ready   |			|	running		|------->| terminated |
|	 	    | admitted	|	        |			|				|  exit  | 			  |
+-----------+			+-----------+			+---------------+      	 +------------+
							|  |	  scheduler patch |		|							
							|  +---------->-----------+	    |
	   IO/ event completion	|								| IO / event waitting
							|								|
							|		+-------------+			|
							+--<----|   waitting  |----<----+
									| 			  |
									+-------------+

4.2、Java线程状态中 RUNNABLE 有如下注释:

操作系统中等待资源(例如CPU)的线程状态对于JVM来说,线程都是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.

4.3、使用 Java 阻塞 I/O 模型读取数据,将会导致线程阻塞,线程将会进入休眠,从而让出 CPU 的执行权,直到数据读取完成。这个期间如果使用 jstack 查看线程状态,却可以发现 Java 线程状态是处于 RUNNABLE,这就和上面说的存在矛盾,为什么会这样?

当线程调用阻塞式 API,线程进入休眠状态,这里指的是操作系统层面的。从 JVM 层面,Java 线程状态依然处于RUNNABLE状态。JVM 并不关心操作系统线程实际状态。从 JVM 看来等待 CPU 使用权(操作系统线程状态为可运行状态)与等待 I/O (操作系统线程状态处于休眠状态)没有区别,都是在等待某种资源,所以都归入 RUNNABLE 状态。


http://www.kler.cn/a/443271.html

相关文章:

  • vue3如何使用bus(事件总线)
  • 一块钱的RISC-V 32位芯片
  • Linux标准IOday3
  • 【Ubuntu】 Ubuntu22.04搭建NFS服务
  • 运行vue项目,显示“npm”无法识别为 cmdlet、函数、脚本文件或可操作程序的名称
  • H5通过URL Scheme唤醒手机地图APP
  • 企业配置NAT出口产生环路怎么办?用户访问服务器的响应速度非常慢,如何解决?
  • Optimal Algorithms:滑动窗口+二分查找
  • LeetCode 1847.最近的房间:有序集合
  • 【漏洞复现】Grafana 安全漏洞(CVE-2024-9264)
  • Spring依赖注入不同类型的数据
  • Java学习教程,从入门到精通,Java Set 接口语法知识点及案例代码(64)
  • [spring]实例化对象(静动态工厂)
  • 鸿蒙项目云捐助第十七讲云捐助我的页面上半部分的实现
  • 苹果将推出超薄和折叠款iPhone,2024年带来哪些变化?
  • 部署 Apache Samza 和 Apache Kafka
  • 基于Hadoop的数据清洗
  • 【Django开发】前后端分离django美多商城项目第11篇:商品数据库表设计,1. SPU介绍【附代码文档】
  • 【蓝桥杯每日一题】求和——前缀和
  • 用QT制作的倒计时软件
  • AIGC--------游戏开发中的AIGC:剧情、角色与场景生成
  • 探秘 MFC 中的 AFX_MANAGE_STATE:确保模块资源管理井然有序
  • 云消息队列 RabbitMQ 版
  • 【杂谈】服务端能同时处理多少个 Socket 连接?背后的资源与限制分析
  • CSS|08 浮动清除浮动
  • 实验6-2 基于二叉链表存储结构实现二叉树的基本操作