详解Java的线程状态

 更新时间:2022年11月06日 08:49:54   作者:UnicornLien  
本文主要为大家详细介绍一下Java的线程状态,文中的示例代码讲解详细,对我们学习有一定的帮助,感兴趣的小伙伴可以跟随小编学习一下

Java的每个线程都具有自己的状态,Thread类中成员变量threadStatus存储了线程的状态:

private volatile int threadStatus = 0;

在Thread类中也定义了状态的枚举,共六种,如下:

public enum State {
    NEW,			//	新建状态
    RUNNABLE,		//	执行状态
    BLOCKED,		//	阻塞状态
    WAITING,		//	无限期等待状态
    TIMED_WAITING,  //  有限期等待状态
    TERMINATED;     //  退出状态
}

threadStatus初始值为0,对应的就是NEW状态。

  • NEW:新建状态,new Thread()时处于这个状态,此时线程还未开始执行
  • RUNNABLE:执行状态,当调用了start方法后,线程处于此状态,当然此刻CPU不一定正在执行它
  • BLOCKED:阻塞状态,线程等待锁时处于此状态
  • WAITING:无限期等待状态,需要被唤醒的等待属于此状态,如Object.wait
  • TIMED_WAITING:有限期等待状态,调用一些有超时时间的等待方法会进入此状态,如Thread.sleep、Object.wait、Thread.join、Lock.tryLock、Condition.await
  • TERMINATED:退出状态,可能是正常运行完毕,也可能是抛出了异常导致线程终止

我们可以通过getState获取线程的状态:

State state = thread.getState();

接下来,我们通过示例来感受线程状态的变化。

示例一:

Thread t = new Thread(() -> {
    System.out.println("sleep");
    //	休眠2秒
    ThreadUtil.sleep(2000);
    System.out.println("run");
});

//	启动前先打印一下线程状态
System.out.println(t.getState());
//	启动线程
t.start();
//	启动后立即打印一次线程状态
System.out.println(t.getState());

//	每隔500毫秒打印一次线程状态
while (true) {
    ThreadUtil.sleep(500);
    System.out.println(t.getState());
}

输出:

NEW
RUNNABLE
sleep
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
run
TERMINATED
TERMINATED
TERMINATED
TERMINATED
TERMINATED
TERMINATED
TERMINATED

可以看出,线程创建后,初始状态为NEW;

调用start方法后状态变更为了RUNNABLE;

当线程内执行了sleep,休眠2秒钟,状态变更为了TIMED_WAITING;

当线程执行完成后,状态变更为了TERMINATED。

示例二:

本示例演示在多线程争抢锁的情况下,线程状态的变化。

private static Object lock = new Object();

public static void main(String[] args) {
    Runnable runnable = () -> {
        //	加锁
        synchronized (lock) {
            System.out.println(Thread.currentThread().getName() + " lock");
            ThreadUtil.sleep(2000);
        }
        System.out.println(Thread.currentThread().getName() + " exit");
    };

    Thread t1 = new Thread(runnable, "t1");
    Thread t2 = new Thread(runnable, "t2");

    t1.start();
    t2.start();

    while (true) {
        ThreadUtil.sleep(500);
        System.out.println(t1.getName() + ":" + t1.getState());
        System.out.println(t2.getName() + ":" + t2.getState());
    }
}

输出:

t1 lock                t1获得了锁
t1:TIMED_WAITING    t1 sleep,进入有限等待状态
t2:BLOCKED          t2未获得锁,因此进入阻塞状态
t1:TIMED_WAITING    
t2:BLOCKED
t1:TIMED_WAITING
t2:BLOCKED
t1 exit             t1释放锁,执行完成,退出
t2 lock             t2获得锁
t1:TERMINATED       t1已经是退出状态
t2:TIMED_WAITING    t2 sleep,进入有限等待状态
t1:TERMINATED       
t2:TIMED_WAITING
t1:TERMINATED
t2:TIMED_WAITING
t1:TERMINATED
t2:TIMED_WAITING
t2 exit            t2释放锁,执行完成,退出
t1:TERMINATED      t1为退出状态
t2:TERMINATED      t2为退出状态

示例三:

本示例演示了线程如何进入和退出WAITING状态。

private static Object obj = new Object();

public static void main(String[] args) {
    Runnable runnable = () -> {
        synchronized (obj) {
            try {
                //	等待
                obj.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("exit");
        }
    };

    Thread t1 = new Thread(runnable, "t1");
    System.out.println(t1.getName() + ":" + t1.getState());
    t1.start();
    System.out.println(t1.getName() + ":" + t1.getState());

    for (int i = 0; i < 20; i++) {
        ThreadUtil.sleep(500);
        if(i == 3) {
            synchronized (obj) {
                //	唤醒
                obj.notify();
            }
        }
        System.out.println(t1.getName() + ":" + t1.getState());
    }
}

输出:

t1:NEW
t1:RUNNABLE
t1:WAITING    调用了obj.wait()进入无限等待状态
t1:WAITING
t1:WAITING
t1:BLOCKED  主线程获得锁,进行notify,t1进入了阻塞状态
exit               t1线程退出同步块,执行完成
t1:TERMINATED  t1线程退出
t1:TERMINATED

Java Thread的threadStatus字段值的更新代码位于hotspot c++源码中,JDK源码中看不到。

Java的线程状态并非是操作系统的实际线程状态,但与操作系统的线程状态是有对应关系的,后续有需要深入分析操作系统原理、hotspot源码再展开。

到此这篇关于详解Java的线程状态的文章就介绍到这了,更多相关Java线程状态内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java实现代码块耗时测算工具类

    Java实现代码块耗时测算工具类

    这篇文章主要为大家介绍了如何利用Java语言编写一个工具类,用来测算代码块的耗时,同时还能显示进度,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-05-05
  • JDK动态代理提高代码可维护性和复用性利器

    JDK动态代理提高代码可维护性和复用性利器

    这篇文章主要为大家介绍了JDK动态代理提高代码可维护性和复用性利器,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • java数据类型与二进制详细介绍

    java数据类型与二进制详细介绍

    这篇文章主要介绍了java数据类型与二进制详细介绍的相关资料,这里对数据类型进行了一一介绍分析,并说明自动转换和强制转换,需要的朋友可以参考下
    2017-07-07
  • spring boot使用logback实现多环境日志配置详解

    spring boot使用logback实现多环境日志配置详解

    这篇文章主要介绍了spring boot使用logback实现多环境日志配置详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • Spring boot整合security详解

    Spring boot整合security详解

    Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架,本文主要介绍了SpringBoot整合Security安全框架的方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07
  • 详解JVM类加载机制及类缓存问题的处理方法

    详解JVM类加载机制及类缓存问题的处理方法

    这篇文章主要给大家介绍了关于JVM类加载机制及类缓存问题的处理方法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-01-01
  • 在windows环境下安装jdk8、jdk9、jdk11、jdk12并自由切换

    在windows环境下安装jdk8、jdk9、jdk11、jdk12并自由切换

    这篇文章主要介绍了在windows环境下安装jdk8、jdk9、jdk11、jdk12并自由切换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • Java 入门图形用户界面设计之事件处理下

    Java 入门图形用户界面设计之事件处理下

    图形界面(简称GUI)是指采用图形方式显示的计算机操作用户界面。与早期计算机使用的命令行界面相比,图形界面对于用户来说在视觉上更易于接受,本篇精讲Java语言中关于图形用户界面的事件处理
    2022-02-02
  • SpringBoot获取当前运行环境三种方式小结

    SpringBoot获取当前运行环境三种方式小结

    在使用SpringBoot过程中,我们只需要引入相关依赖,然后在main方法中调用SpringBootApplication.run(应用程序启动类.class)方法即可,那么SpringBoot是如何获取当前运行环境呢,接下来由小编给大家介绍一下SpringBoot获取当前运行环境三种方式,需要的朋友可以参考下
    2024-01-01
  • 基于SpringBoot生成二维码的几种实现方式

    基于SpringBoot生成二维码的几种实现方式

    本文将基于Spring Boot介绍两种生成二维码的实现方式,一种是基于Google开发工具包,另一种是基于Hutool来实现,具有一定的参考价值,感兴趣的可以了解一下
    2022-03-03

最新评论