JAVA 并发编程 线程状态

简介: Thread.State 枚举类中记录了 Java 中定义的线程状态信息。
public enum State {
    // (新建)
    NEW,
    // (准备就绪)(RUNABLE又可以细分为两个状态:READY和RUNNING)
    RUNNABLE,
    // (阻塞)
    BLOCKED,
    // (持续等待)
    WAITING,
    // (暂时等待)
    TIMED_WAITING,
    // (终结)
    TERMINATED;
}

注意:可运行状态不一定就是在运行,因为CPU时间片是由操作系统分配的,只有操作系统给线程分配了CPU时间片,这条线程才真正的Running。所以Runnable可简单分为Ready与Running两种状态。由New到Runnable再到Terminated,这几个状态是不可逆的。

  • New 状态:如果线程没有开始运行 start() 方法,所以也没有开始执行 run() 方法里面的代码,那么此时它的状态就是 New。而一旦线程调用了start(),它的状态就会从 New 变成 Runnable。
  • Runnable 状态:

Java 中的 Runable 状态对应操作系统线程状态中的两种状态,分别是 Running 和 Ready,也就是说,Java 中处于 Runnable 状态的线程有可能正在执行,也有可能没有正在执行,正在等待被分配 CPU 资源。

所以,如果一个正在运行的线程是 Runnable 状态,当它运行到任务的一半时,执行该线程的 CPU 被调度去做其他事情,导致该线程暂时不运行,它的状态依然不变,还是 Runnable,对应到操作系统,此时状态已变为Ready,因为它有可能随时被调度回来继续执行任务。

  • Blocked 状态:从 Runnable 状态进入 Blocked 状态只有一种可能,就是进入 synchronized 保护的代码时没有抢到 monitor 锁 ,此时就会阻塞。此时,线程将会等待monitor锁被其它线程释放,然后抢占monitor锁,一旦抢占成功,那么当前线程就会从Blocked状态转回Runnable状态。假设永远抢占不到,那么就永远阻塞。
  • Waiting 状态:

Runnable状态和 Waiting状态可相互流转,Waiting状态是一种和Blocked状态类似的阻塞状态,但触发条件不一样。以下三种方法可使线程从Runnable转为Waiting状态。

  • Object.wait() 方法
  • Thread.join() 方法
  • LockSupport.park() 方法

注意到这些方法都是无参数的,一旦被调用,只能在某种条件下,才能从Waiting状态转回Runnable状态。Object.wait()方法被调用后,只能通过Object.notify()或Object.notifyAll()方法来唤醒。由于Object.wait()方法通常和synchronized关键字配合使用以避免程序出错,所以在Object.notify()后都需要去抢占monitor锁,没抢占到的将会进入到Blocked状态以等待锁。(上图没体现这点,这是因为,不配合synchronized关键字使用在语法上没任何问题,只是会导致一些不可预估的错误,后续文章将会详细介绍)。

Thread.join() 方法调用后也会进入Waiting状态,此时,原线程只需要等待join进来的线程执行完或被中断即可恢复到Runnable。

LockSupport.park()方法调用后进入Waiting状态,此时,只需要等待其它线程执行LockSupport.unpark()方法即可恢复到Runnable。

  • Time Waiting 状态:

Timed Waiting和 Waiting可以认为是差不多的。区别仅在于有没有时间限制,Timed Waiting 会等待超时,由系统自动唤醒,或者在超时前被唤醒信号唤醒。进入Time Waiting的方法会添加等待时间参数,当线程在等待时间结束后,系统就会唤醒该线程,如果线程需要monitor锁才能运行,那么会先抢占monitor锁,抢不到的线程自然又会流转到Blocked状态。

  • Terminated 状态:

终止状态是线程的最后一个状态,终止后,线程占用的资源将会被操作系统回收。线程终止有两种可能,一是线程正常执行完毕,二是出现一个没有捕获的异常,终止了 run() 方法,最终导致意外终止。

相关文章
|
8天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
2天前
|
数据采集 存储 数据处理
Python中的多线程编程及其在数据处理中的应用
本文深入探讨了Python中多线程编程的概念、原理和实现方法,并详细介绍了其在数据处理领域的应用。通过对比单线程与多线程的性能差异,展示了多线程编程在提升程序运行效率方面的显著优势。文章还提供了实际案例,帮助读者更好地理解和掌握多线程编程技术。
|
1天前
|
API Android开发 iOS开发
深入探索Android与iOS的多线程编程差异
在移动应用开发领域,多线程编程是提高应用性能和响应性的关键。本文将对比分析Android和iOS两大平台在多线程处理上的不同实现机制,探讨它们各自的优势与局限性,并通过实例展示如何在这两个平台上进行有效的多线程编程。通过深入了解这些差异,开发者可以更好地选择适合自己项目需求的技术和策略,从而优化应用的性能和用户体验。
|
7天前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
|
7天前
|
Java 开发者
Java多线程编程的艺术与实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的技术文档,本文以实战为导向,通过生动的实例和详尽的代码解析,引领读者领略多线程编程的魅力,掌握其在提升应用性能、优化资源利用方面的关键作用。无论你是Java初学者还是有一定经验的开发者,本文都将为你打开多线程编程的新视角。 ####
|
6天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
Java
华为技术专家深度解析Java线程状态(下)
华为技术专家深度解析Java线程状态
127 0
华为技术专家深度解析Java线程状态(下)
|
16天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
12天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
36 9
|
9天前
|
安全 Java 开发者
Java多线程编程中的常见问题与解决方案
本文深入探讨了Java多线程编程中常见的问题,包括线程安全问题、死锁、竞态条件等,并提供了相应的解决策略。文章首先介绍了多线程的基础知识,随后详细分析了每个问题的产生原因和典型场景,最后提出了实用的解决方案,旨在帮助开发者提高多线程程序的稳定性和性能。
下一篇
无影云桌面