Java 多线程——线程状态和线程分析

线程状态

NEW

这是线程创建但尚未启动时的状态。例如,当您使用构造函数创建一个新的 Thread 对象时,该线程就处于新状态。只能在新线程上调用start()方法;否则,将抛出 IllegalThreadStateException。

RUNNABLE

这是线程准备好运行并等待 CPU 时间时的状态。例如,当您在新线程上调用 start() 方法时,或者当阻塞或等待线程有资格再次运行时。线程调度程序根据线程的优先级和其他因素从可运行状态中选择一个线程来执行。

RUNNING

这是线程在 CPU 上执行时的状态。例如,当线程调度程序从可运行状态中挑选一个线程并将其分配给CPU核心时,该线程就处于运行状态。线程执行其 run() 方法并执行其任务。线程只有从可运行状态才能进入运行状态。

BLOCKED

这是一个线程等待获取另一个线程持有的监视器锁时的状态。例如,当一个线程尝试进入已被另一个线程占用的同步块或方法时,该线程将被阻塞,直到锁被释放。线程可以从运行状态进入阻塞状态,获得锁后又可以回到可运行状态。

WAITING

这是线程无限期等待另一个线程执行某个操作时的状态。例如,当一个线程调用一个对象的wait()方法,或者另一个线程的join()方法,或者LockSupport类的park()方法时,该线程就处于等待状态。线程可以从运行状态进入等待状态,并且当收到通知或中断时可以返回到可运行状态。

TIMED WAITING

这是一个线程等待另一个线程执行特定操作指定的时间时的状态。例如,当线程调用 sleep() 方法、带超时参数的 wait() 方法、带超时参数的 join() 方法、LockSupport 类的 ParkNanos() 或 ParkUntil() 方法时,线程处于定时等待状态。线程可以从运行状态进入定时等待状态,当超时或收到通知或中断时可以返回到可运行状态。

TERMINATED

这是线程完成执行或由于异常或错误而中止时的状态。例如,当线程正常或异常完成其 run() 方法时,或者通过调用 stop() 方法(已弃用)停止线程时,该线程就处于终止状态。线程只能从运行状态进入终止状态,而不能返回到任何其他状态。

当线程等待 I/O 操作完成时,线程处于什么状态?— 它是阻塞等待或定时等待,具体取决于 I/O 操作的类型和使用的 API。当线程执行传统的阻塞 I/O 操作(例如读取文件或套接字)时,它会进入阻塞状态并等待 I/O 操作完成。但是,某些 I/O 操作可能有一个超时参数,用于指定线程应等待操作完成的时间。在这种情况下,线程进入定时等待状态并等待操作完成或超时到期。

操作系统能否将执行同步块的线程中途置于阻塞状态并调度正在等待锁的阻塞线程?— 不会。这是因为同步块确保一次只有一个线程可以进入该块,并且进入该块的线程会获取用于同步的对象的监视器锁。操作系统无法中断或抢占持有监视器锁的线程,除非该线程通过退出块或调用对象上的 wait() 来自愿释放锁。

线程分析

线程分析可以帮助我们了解线程处于什么状态以及为什么。我们还可以查看线程是否能够并行运行(即查看线程的并发级别)。它还告诉我们线程在不同状态下花费了多少时间。我们还可以查找并分析高锁争用的案例。我们将使用 Java Flight Recorder (JFR) 来分析线程。

当我们使用 JFR 分析我们的应用程序时,它将显示不同的线程事件。让我们尝试将这些线程事件映射到我们上面讨论的状态:

Java 线程停放

当线程调用 LockSupport.park() 方法或其变体时,会发生此事件,这会导致线程挂起其执行,直到被另一个线程取消停放或超时到期。这通常被并发实用程序(例如 java.util.concurrent.locks)用来实现有效的阻塞机制。该事件对应于等待定时等待状态,具体取决于是否使用超时参数调用park()方法。

Java 线程睡眠

当线程调用 Thread.sleep() 方法或其变体时,会发生此事件,这会导致线程将其执行挂起指定的时间。这通常用于在执行流程中引入延迟或暂停。该事件对应于定时等待状态。

Java 监视器等待

当线程调用 Object.wait() 方法或其变体时,会发生此事件,这会导致线程释放对象的监视器(锁)并等待,直到收到另一个线程的通知或超时到期。这通常用于实现线程间的通信和协调。此事件对应于等待定时等待状态,具体取决于是否使用超时参数调用 wait() 方法。

Java 监视器被阻止

当线程尝试获取已由另一个线程拥有的对象的监视器锁(在同步方法/块内)时,会发生此事件,这会导致线程阻塞,直到监视器被释放。这通常用于实现互斥和同步。该事件对应于阻塞状态。

套接字读取

当线程调用 SocketInputStream.read() 方法或其变体时,会发生此事件,这会导致线程从套接字读取数据。这通常用于实现网络通信。该事件对应于阻塞状态。

套接字写入

当线程调用 SocketOutputStream.write() 方法或其变体时,会发生此事件,这会导致线程将数据写入套接字。这也经常用于实现网络通信。该事件对应于阻塞状态。

文件读取

此事件表示线程正在使用 File 类或其子类的 read() 方法从文件中读取数据。该方法可以阻塞线程,直到有一些数据可用或发生异常。该事件对应于阻塞状态。

文件写入

此事件表示线程正在使用 File 类或其子类的 write() 方法将数据写入文件。该方法可以阻塞线程,直到数据写入或者发生异常。该事件对应于阻塞状态。

© 版权声明
THE END
喜欢就支持一下吧
点赞0打赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容