java线程的几种状态

目录

正文:

1.JConsole

2.新建状态(New)

3.运行状态(Runnable)

4.阻塞状态(Blocked)

5.等待状态(Waiting)

6.计时等待状态(Timed Waiting)

7.终止状态(Terminated)

总结:


正文:

1.JConsole

JConsole是Java监控和管理控制台工具,是Java Development Kit(JDK)中自带的一个图形化工具,用于监视和管理Java应用程序的性能和资源消耗情况。通过JConsole,可以实时查看Java虚拟机(JVM)的运行状态、线程信息、内存使用情况、类加载信息等。要通过JConsole查看线程的状态,你需要先确保你的Java应用程序已经启动,并且JConsole已经附加到该应用程序的进程上。JConsole是Java的一个监控和管理工具,它可以用来监控Java虚拟机(JVM)的性能和资源使用情况,包括线程的状态。

以下是使用JConsole查看线程状态的步骤:

  1. 启动JConsole

    • 在命令行中输入jconsole命令并回车,或者在Java安装目录的bin文件夹中找到jconsole可执行文件并运行它。
  2. 附加到进程

    • 在JConsole启动后,它会显示一个列表,其中包含当前用户可以访问的所有Java进程。
    • 从列表中选择你想要监控的Java应用程序的进程,并点击“Connect”按钮。
  3. 查看线程状态

    • 连接成功后,JConsole的主界面会显示多个选项卡。点击“Threads”选项卡。
    • 在“Threads”选项卡中,你可以看到当前JVM中所有线程的列表,包括每个线程的ID、名称、状态(如Runnable、Waiting、Blocked等)和优先级。
    • 你可以通过点击线程列表中的线程来查看更多关于该线程的详细信息,如堆栈跟踪、锁信息等。
  4. 分析线程状态

    • 使用JConsole提供的线程信息,你可以分析线程的状态和行为,识别可能的性能问题或死锁。
    • 如果需要,你可以在JConsole中对线程进行操作,如暂停、恢复或终止线程。

请注意,JConsole只能附加到已经在运行的Java进程上。如果你的应用程序还没有启动,你需要先运行它,然后再使用JConsole来监控。

此外,JConsole的使用可能受到操作系统的安全限制,确保你有足够的权限来附加到目标进程。如果你在使用JConsole时遇到问题,确保你的Java环境和JVM设置是正确的,并且你有足够的权限来执行监控操作。

2.新建状态(New)

线程的新建状态(New State)是线程生命周期中的第一个状态。当一个Thread对象被实例化后,此时线程对象被创建但还没有调用start()方法时,线程处于新建状态。此时线程对象已经在内存中,但尚未启动。

特点:

  • 初始化:在新建状态下,线程对象已经被创建,但还没有分配系统资源,如CPU时间片和内存。
  • 未启动:线程尚未被启动,即start()方法还未被调用。
  • 不可见:在新建状态下,线程对其他线程不可见,它还没有加入到可运行的线程队列中。
  • 可配置:在新建状态下,可以在启动线程之前设置线程的属性,如优先级、名称、是否为守护线程等。

状态转换:

  • 新建到就绪:当对线程对象调用start()方法时,线程会从新建状态转换到就绪状态。在就绪状态下,线程等待操作系统调度器的调度,以便在CPU上执行。
  • 新建到终止:如果在新建状态下,线程对象被垃圾收集器回收,那么线程将直接进入终止状态,而不会执行任何操作。

代码实例:

public class NewThreadExample {public static void main(String[] args) {// 创建线程对象,此时线程处于新建状态Thread thread = new Thread(() -> {System.out.println("Thread is running...");});// 线程对象创建后,可以设置其属性,如优先级thread.setPriority(Thread.MAX_PRIORITY);//线程启动之前查看状态,结果为(NEW)System.out.println(thread.getState());// 启动线程,使其进入就绪状态thread.start();//线程启动之后查看状态System.out.println(thread.getState());}
}

运行结果如下:

可以看到调用start后状态发生了改变。

3.运行状态(Runnable)

在线程处于RUNNABLE(运行状态)时,称为可工作的,又可以分成正在工作中和即将开始工作。即将开始工作表示这个线程虽然没在CPU执行,但是可以随时调度到CPU执行。开始工作表示线程正在执行任务代码。在这个状态下,线程已经被操作系统的线程调度器分配了CPU时间片,并且正在运行代码。这是线程生命周期中的一个活跃阶段,在这个状态下,线程实际在进行工作。

特点:

  • 执行中:线程正在CPU上执行其任务或准备执行。
  • 消耗资源:在运行状态下,线程消耗CPU资源。
  • 调度:线程的运行由操作系统的调度器管理。调度器根据线程的优先级、调度策略和其他因素决定线程的执行顺序。
  • 时间片:线程获得的CPU时间是有限的,通常称为时间片。时间片用完或者操作系统决定执行其他线程时,当前运行的线程可能会被挂起,从而转换到就绪状态。

状态转换:

  • 从就绪到运行:当操作系统调度器选择一个就绪状态的线程并分配CPU时间片时,该线程状态变为运行。
  • 从运行到就绪:当线程的时间片用完或者线程显式地让出CPU(例如,调用Thread.yield())时,它会回到就绪状态,等待下一次被调度。
  • 从运行到阻塞:如果运行中的线程尝试获取一个已经被其他线程持有的锁,或者等待I/O操作完成,它会进入阻塞状态。
  • 从运行到终止:当线程的run()方法执行完毕或者在run()方法中抛出一个未捕获的异常时,线程进入终止状态。

我们通过死循环不停止线程,进入jconsole查看一下状态

public class test {public static void main(String[] args) {Thread t1 = new Thread(() -> {while (true) System.out.println("hello t1");}, "t1线程");t1.start();while (true) {System.out.println("hello main");}}
}

我们主要看t1线程和主线程 

这两个线程都已经启动起来了,所以状态自然都是RUNNABLE 

4.阻塞状态(Blocked)

线程的阻塞状态(Blocked State)是指线程因为等待获取一个监视器锁(monitor lock)而暂时停止执行的状态。这种状态通常发生在线程尝试进入一个已经被其他线程持有的同步块时。在阻塞状态下,线程无法执行任何操作,直到它获得所需的锁。

特点:

  • 等待获取锁:一个常见的情况是线程在同步代码块或同步方法中试图获取一个对象的锁,但该锁已经被其他线程持有。在这种情况下,线程会被阻塞,直到锁被释放。这种阻塞状态被称为同步阻塞。

  • 等待I/O操作完成:线程在执行I/O操作时(如读取文件、网络通信等),可能会因为需要等待I/O操作完成而被阻塞。在这种情况下,线程会暂时停止执行,直到I/O操作完成并数据准备好。这种阻塞状态被称为I/O阻塞。

  • 等待其他线程通知:线程在调用wait()方法后会进入等待状态,直到其他线程调用notify()或notifyAll()方法来唤醒它。因此,线程可能会因为等待其他线程的通知而被阻塞。这种阻塞状态被称为等待阻塞。

  • 等待条件满足:线程在某些情况下需要等待特定条件满足才能继续执行,如果条件不满足,则线程会被阻塞。在这种情况下,线程可能会因为等待条件满足而被阻塞。这种阻塞状态被称为条件阻塞。

  • 竞争资源:多个线程之间可能会竞争共享资源,如果资源被其他线程占用或者无法获取到需要的资源,线程可能会被阻塞。在这种情况下,线程会等待资源可用时才能继续执行。

  • 解除阻塞:线程在阻塞状态下会等待某些条件满足或者其他线程的操作,一旦条件满足或者被唤醒,线程会从阻塞状态转变为就绪状态,等待操作系统的线程调度器分配CPU时间片,继续执行任务代码。

状态转换:

  • 从运行到阻塞:当运行状态的线程尝试获取一个已经被其他线程持有的锁时,它会进入阻塞状态。
  • 从阻塞到运行:当持有所需锁的线程释放锁(通过退出同步块或同步方法),阻塞的线程会被唤醒并重新进入就绪状态,等待再次获得CPU时间片以执行。
  • 从阻塞到终止:如果阻塞的线程在等待锁的过程中被中断(通过Thread.interrupt()方法),它可能会进入终止状态。

代码实例:

public class BlockExample {private static final Object lock = new Object();public static void main(String[] args) {Thread thread1 = new Thread(() -> {synchronized (lock) {System.out.println("Thread 1 acquired lock");// 模拟长时间操作try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}});Thread thread2 = new Thread(() -> {synchronized (lock) {System.out.println("Thread 2 acquired lock");// 模拟操作}});thread1.start(); // 启动thread1,它会首先获取锁thread2.start(); // 启动thread2,它会尝试获取已经被thread1持有的锁,因此进入阻塞状态}
}

在这个例子中,thread2在尝试进入同步块时会因为lock已经被thread1持有而进入阻塞状态。只有当thread1释放锁(在这个例子中是通过Thread.sleep(5000)完成后)时,thread2才能获取锁并开始执行。

我们利用死循环进入jconsole查看状态

public class test {private static final Object resource = new Object();public static void main(String[] args) {Thread thread1 = new Thread(() -> {synchronized (resource) {while(true)System.out.println("Thread 1: Locked resource");}},"t1");thread1.start(); // 启动thread1,它会首先获取资源锁Thread thread2 = new Thread(() -> {synchronized (resource) {// 这里会等待,直到thread1释放锁System.out.println("Thread 2: Locked resource");}},"t2");thread2.start(); // 启动thread2,它会尝试获取已被thread1持有的资源锁,因此进入阻塞状态}
}

该代码t1会先拿到锁,然后进入死循环,t2会一直被阻塞等待t1释放锁。 

5.等待状态(Waiting)

在Java中,线程的等待状态(Waiting State)是指线程在等待另一个线程执行特定操作时的状态。这种状态与阻塞状态类似,但有一个关键的区别:在等待状态中,线程等待的不是锁,而是其他线程执行的操作,如通知(notification)或中断(interruption)。等待状态是无限期的,除非另一个线程执行了特定的操作来唤醒等待的线程。

特点:

  • 无限期等待:线程在等待状态中会一直等待,直到接收到另一个线程的通知。
  • 不消耗CPU:在等待状态中,线程不会消耗CPU资源,因为它不执行任何代码。
  • 可被中断:即使在等待状态中,线程也可以被中断。如果线程在等待时收到中断信号,它会抛出InterruptedException,并根据线程的中断策略决定下一步的行为。
  • 依赖协作:等待状态的线程依赖于其他线程的特定操作来继续执行。

状态转换:

  • 从运行到等待:线程调用Object.wait()Thread.join()或类似的方法,且没有指定等待时间,会从运行状态转换到等待状态。
  • 从等待到运行:当另一个线程调用与等待状态相对应的通知方法(如Object.notify()Object.notifyAll())时,等待的线程会被唤醒,并尝试重新获取锁,然后返回到运行状态。
  • 从等待到阻塞:如果等待的线程在等待时被中断,它可能会转换到阻塞状态,尝试获取锁。
  • 从等待到终止:如果等待的线程在等待时被中断,并且线程的中断策略是退出等待状态,那么它将转换到终止状态。

实例代码:

public class WaitingExample {public static void main(String[] args) {Thread waitingThread = new Thread(() -> {synchronized (WaitingExample.class) {System.out.println("Waiting thread is waiting for notification");try {WaitingExample.class.wait(); // 进入等待状态} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Waiting thread has been notified and is running again");}});Thread notifyingThread = new Thread(() -> {synchronized (WaitingExample.class) {// 让等待的线程等待一段时间try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}WaitingExample.class.notify(); // 唤醒等待的线程}});waitingThread.start(); // 启动等待的线程notifyingThread.start(); // 启动通知的线程}
}

在这个例子中,waitingThread调用了wait()方法并进入等待状态。notifyingThread在一段时间后调用了notify()方法,这将唤醒等待的线程。waitingThread在接收到通知后,会从等待状态转换回运行状态,并继续执行。 

同样改写代码进入jconsole查看

public class test {public static void main(String[] args) {Thread t = new Thread(() -> {while(true){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();try {//死等t.join();} catch (InterruptedException e) {e.printStackTrace();}}
}

 通过join让main线程等待t完成,在等待的期间main就是无休止的等待状态WAITING

6.计时等待状态(Timed Waiting)

在Java中,计时等待状态(Timed Waiting State)是指线程在等待一个确定的时间长度后自动唤醒的状态。这种状态与等待状态(Waiting State)相似,但关键区别在于计时等待有一个超时时间,线程会在超时后自动继续执行,而不需要其他线程的干预。

特点:

  • 有限等待:线程在计时等待状态中等待一个特定的时间长度。
  • 自动唤醒:一旦超时时间到达,线程会自动从计时等待状态转换到运行状态(Runnable),并尝试重新获取锁。
  • 可中断:计时等待状态中的线程可以被中断。如果线程在计时等待期间收到中断信号,它会抛出InterruptedException,并根据线程的中断策略决定下一步的行为。
  • 超时时间:超时时间是线程进入计时等待状态时设定的,一旦设定,即使线程在等待期间被中断,也会在超时时间到达后自动唤醒。

状态转换:

  • 从运行到计时等待:线程调用了带有超时时间参数的方法,如Thread.sleep(long millis)Object.wait(long timeout)Thread.join(long millis)等,会从运行状态转换到计时等待状态。
  • 从计时等待到运行:当超时时间到达后,线程会自动转换到运行状态,并等待CPU时间片以继续执行。
  • 从计时等待到阻塞:如果线程在计时等待期间被中断,并且线程的中断策略是立即退出等待状态,那么它可能会尝试获取锁并进入阻塞状态。
  • 从计时等待到终止:如果线程在计时等待期间被中断,并且线程的中断策略是抛出异常,那么线程可能会抛出InterruptedException并终止执行。

代码实例:

public class TimedWaitingExample {public static void main(String[] args) {Thread thread = new Thread(() -> {System.out.println("Thread is entering timed waiting state");try {// 线程进入计时等待状态,等待2000毫秒(2秒)Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Thread has woken up from timed waiting state");});thread.start(); // 启动线程}
}

改变代码查看jconsole

public class test {public static void main(String[] args) {Thread t = new Thread(() -> {while(true){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();try {//有时间限制的等待t.join(3600 * 1000);} catch (InterruptedException e) {e.printStackTrace();}}
}

 这段代码和Waiting状态的大体一样,唯一不同的就是join在调用时限制了等待的时间,在超过时间后会被唤醒。此时main的状态就变成了TIMED_WAITING。

7.终止状态(Terminated)

在Java中,终止状态(Terminated State)是线程生命周期的最终状态。当线程的run()方法执行完毕,或者线程因为某种原因被中断且没有可执行的代码时,线程就会进入终止状态。

特点:

  • 执行结束:线程的run()方法已经执行完毕,或者线程在执行过程中遇到了未捕获的异常。
  • 不可恢复:一旦线程进入终止状态,它就不能再被恢复到运行状态或任何其他状态。
  • 资源释放:线程相关的系统资源,如内存、锁等,通常会在线程终止后被释放。
  • 垃圾收集:线程对象本身在终止后会成为垃圾收集器的回收目标,最终被清除。

状态转换:

  • 从运行到终止:线程的run()方法正常执行完毕,或者线程在执行过程中抛出了一个未被捕获的异常,线程会进入终止状态。
  • 从阻塞到终止:如果线程在阻塞状态(如等待输入输出操作、等待进入同步块等)时被中断,且中断后没有更多的代码需要执行,线程也会进入终止状态。
  • 从等待到终止:如果线程在等待状态(如调用Object.wait())时被中断,且中断后没有更多的代码需要执行,线程同样会进入终止状态。

 代码实例:

public class test {public static void main(String[] args) {Thread thread = new Thread(() -> {System.out.println("Thread is running...");// 模拟线程执行完毕});thread.start(); // 启动线程try {thread.join(); // 等待线程终止} catch (InterruptedException e) {e.printStackTrace();}//获取线程对象,查看状态System.out.println(thread.getState());}
}

在这个例子中,当threadrun()方法执行完毕后,它将进入终止状态。主线程通过调用thread.join()等待子线程终止。

运行结果如下:

总结:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/794667.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ABAP 读取EXCEL 文件内容,函数 TEXT_CONVERT_XLS_TO_SAP

EXCEL 内容: 读取内容: 代码: TYPES: BEGIN OF ITAB, FL1(50) TYPE C, FL2(50) TYPE C, FL3(50) TYPE C, FL4(50) TYPE C, FL5(50) TYPE C, FL6(50) TYPE C, END OF ITAB. DATA: T_ITEM TYPE TABLE OF ITAB WITH HEADER LINE. TYPE…

Netty经典32连问

文章目录 1、Netty是什么,它的主要特点是什么?2、Netty 应用场景了解么?3、Netty 核心组件有哪些?分别有什么作用?4、Netty的线程模型是怎样的?如何优化性能?5、EventloopGroup了解么?和 Event…

PWM方式读取AS5600磁编码器数据

PWM方式读取AS5600磁编码器获取角度例程 📍相关篇《STM32 软件I2C方式读取AS5600磁编码器获取角度例程》📌《HAL STM32 硬件I2C方式读取AS5600磁编码器获取角度例程》🎉本例程包含:Arduino测试代码、STM32标准库代码、HAL STM32代…

Mac删除软件,动一动手指,几秒就彻底删除 mac删除软件删不掉的解决方法 mac删除软件后怎么删除软件数据

当你入职新公司,接手前任员工使用的Mac电脑时,很可能会遇到一个非常普遍的问题:电脑中装有大量你不需要的软件。这些软件不仅占用宝贵的硬盘空间,还可能影响电脑的运行速度和效率。为了获得一个干净、清爽的使用体验,删…

Java 关键字 this 使用详解(通俗易懂)

this关键字主要有以下三个地方使用 在方法体中引用当前对象,即其方法被调用的对象,以便将当前对象的实例变量或当前对象作为参数传递给其他方法。 ① t this.x; 要在方法中引用当前对象,可以使用关键字 this。 ② return this; 作为当前…

[java]网络编程

网络编程概述 计算机网络: 把分布在不同地理区域的具有独立功能的计算机,通过通信设备与线路连接起来,由功能完善的软件实现资源共享和信息传递的系统。 Java是 Internet 上的语言,它从语言级上提供了对网络应用程序的支持,程序…

题库管理系统-基于Springboot实现JAVA+SQL离散数学题库管理系统(完整源码+LW+翻译)

基于Springboot实现JAVASQL离散数学题库管理系统(完整源码LW翻译) 概述: 本系统具体完成的功能如下: 1题库的管理与维护:新题的录入,修改,删除等功能。 2生成试卷:包括自动生成与手工改动,要…

使用msf进行有防火墙限制的3389端口转发

使用msf进行有防火墙限制的3389端口转发 这里主要是针对在内网中遇到需要开启3389的时候,发现存在防火墙,就没有办法直接远程连接,这个时候就可以使用端口转发使用msf,使用前记得先初始化,连接好数据库这里先使用msf进…

二.音视频编辑-媒体组合-播放

引言 当涉及到音视频编辑时,媒体资源的提取和组合是至关重要的环节。在iOS平台上,AVFoundation框架提供了丰富而强大的功能,使得媒体资源的操作变得轻松而高效。从原始的媒体中提取片段,然后将它们巧妙地组合成一个完整的作品&am…

51之定时器与中断系统

目录 1.定时器与中断系统简介 1.1中断系统 1.2定时器 1.2.1定时器简介 1.2.2定时器大致原理及其配置 1.2.3定时器所需的所有配置总介 2.定时器0实现LED闪烁 3.使用软件生成定时器初始化程序 1.定时器与中断系统简介 1.1中断系统 首先,我们需要来了解一下什么…

深入浅出 -- 系统架构之单体到分布式架构的演变

一、传统模式的技术改革 在很多年以前,其实没有严格意义上的前后端工程师之分,每个后端就是前端,同理,前端也可以是后端,即Ajax、jQuery技术未盛行前的年代。 起初,大部分前端界面很简单,显示的…

AcWing1402.星空之夜

【题目链接】1402. 星空之夜 - AcWing题库 夜空深处,闪亮的星星以星群的形式出现在人们眼中,形态万千。 一个星群是指一组非空的在水平,垂直或对角线方向相邻的星星的集合。 一个星群不能是一个更大星群的一部分。 星群可能是相似的。 如…

【蓝桥杯】GCD与LCM

一.概述 最大公约数(GCD)和最小公倍数(Least Common Multiple,LCM) 在C中,可以使用 std::__gcd(a, b)来计算最大公约数 1.欧几里德算法/辗转相除法 int gcd(int a,int b){return b?gcd(b, a%b):a; } 2…

Tensorboard以及Transforms初步学习

一.前情提要 1.本文是代码结合知识点,注释即为知识点 2.主要详细讲解Tensorboard以及Transforms代码以及基础知识 3.若想深入学习,建议阅读 P3. Python学习中的两大法宝函数(当然也可以用在PyTorch)_哔哩哔哩_bilibili 二.简述…

抖音运营技巧

1、视频时长 抖音的作品是否能够继续被推荐,取决于综合数据,包括完播率、点赞率、评论率、转发率和收藏率等。其中,完播率是最容易控制的因素。对于新号来说,在没有粉丝的初期,发布过长的视频可能会导致无人观看。因此…

金田金业带你一文了解现货黄金开户注意事项

现货黄金作为一种受欢迎的投资品种,吸引了越来越多的投资者。然而,在进行现货黄金开户时,有一些重要的注意事项需要牢记。本文将为您详细介绍现货黄金开户的九大关键要点,确保您能够在投资过程中做出明智的决策。 第一&#xff0c…

Java- maven下载jar包,提示找不到,Could not find artifact

1、执行下面命令行 mvn install:install-file -Dfile/home/quangang/桌面/isv-sdk-2.0.jar -DgroupIdcom.jd -DartifactIdisv-sdk -Dversion2.0 -Dpackangjar 2、然后这里要加上jar包

No dashboards are active for the current data set.

再次记录一下这个离谱的问题 之前出现这个问题是因为目录没写对 今天遇到这个问题的原因是目录是对的,跟目录是否带有中文也没关系 是writer写入的时候写的是空的,离谱的是写入是空的情况下也会生成events日志文件,看起来好像成功写入了一样&…

Spring源码解析上

spring源码解析 整体架构 defaultListableBeanFactory xmlBeanDefinitionReader 创建XmlBeanFactory 对资源文件进行加载–Resource 利用LoadBeandefinitions(resource)方法加载配置中的bean loadBeandefinitions加载步骤 doLoadBeanDefinition xml配置模式 validationMode 获…

2024-04-05 问AI: 介绍一下深度学习中的Leaky ReLU函数

文心一言 Leaky ReLU(Leaky Rectified Linear Unit)函数是深度学习领域中的一种激活函数,主要用于解决ReLU(Rectified Linear Unit)函数在负值区域为零的问题。ReLU函数在输入为正时保持原样,而在输入为负…