线程生命周期与常用方法详解:从新建到终止的全面解析

16 阅读5分钟

线程的生命周期与常用方法

线程是操作系统能够进行运算调度的最小单位。

它被包含在进程之中,是进程中的实际运作单位。

线程的生命周期描述了线程从创建到终止的过程,而常用方法则提供了控制和交互线程的手段。

线程的生命周期

线程的生命周期包括以下几个状态:

  1. 新建状态(New):线程对象被创建,但还没有调用start()方法,因此线程还没有开始执行。
  2. 就绪状态(Runnable):当调用线程的start()方法后,线程就进入就绪状态。在这个状态下,线程只是进入了线程队列,等待CPU的调度,并不代表线程立即就能执行。
  3. 运行状态(Running):线程获得CPU时间片后,它就开始执行run()方法中的代码,进入运行状态。
  4. 阻塞状态(Blocked):线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况包括:等待I/O操作的完成、等待获取一个锁、等待从Thread.sleep()方法返回等。
  5. 死亡状态(Dead):线程执行完run()方法后,或者因为异常退出了run()方法,该线程结束生命周期。

线程的常用方法

线程的常用方法包括:

  1. start():使该线程开始执行;Java虚拟机调用该线程的run()方法。
  2. run():如果该线程是使用独立的Runnable运行对象构造的,则调用该Runnable对象的run()方法;否则,该方法不执行任何操作并返回。
  3. currentThread():返回对当前正在执行的线程对象的引用。
  4. isAlive():测试线程是否处于活动状态。
  5. sleep(long millis):在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。
  6. join():等待该线程终止。
  7. yield():暂停当前正在执行的线程对象,并执行其他线程。
  8. interrupt():中断线程。如果线程在调用Object类的wait()、wait(long)或wait(long, int)方法,或者该类的join()、join(long)、join(long, int)、sleep(long)或sleep(long, int)方法过程中受阻,则其中断状态将被清除,它还将收到一个InterruptedException。

这些方法提供了创建、启动、控制和终止线程的能力,是Java多线程编程的基础。为了更直观地讲解线程的生命周期与常用方法,我将通过示例来说明。

线程的生命周期示例

假设我们有一个简单的Java程序,它创建并启动了一个线程。这个线程的生命周期可以大致分为以下几个阶段:

public class ThreadLifecycleExample {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            try {
                // 模拟线程执行任务
                Thread.sleep(1000); // 线程可能处于TIMED_WAITING状态
                System.out.println("Thread is running...");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // 线程处于 NEW 状态
        System.out.println("Thread state after creation: " + thread.getState()); // 输出 NEW

        // 启动线程,线程进入 RUNNABLE 状态
        thread.start();
        System.out.println("Thread state after calling .start(): " + thread.getState()); // 输出 RUNNABLE,注意此时线程可能还未真正运行

        // 等待线程结束
        try {
            thread.join(); // 主线程等待子线程结束
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        // 线程执行完毕,进入 TERMINATED 状态
        System.out.println("Thread state after completion: " + thread.getState()); // 输出 TERMINATED
    }
}

在这个示例中,线程的生命周期经历了以下阶段:

  1. 新建状态(NEW):线程对象被创建,但尚未启动。
  2. 可运行状态(RUNNABLE):调用线程的start()方法后,线程进入可运行状态,等待CPU调度执行。注意,RUNNABLE状态包括了传统意义上的就绪和运行两种状态。
  3. 运行状态(实际上在RUNNABLE状态内):线程获得CPU时间片后执行run()方法中的代码。
  4. 可能进入的阻塞或等待状态:在这个例子中,线程通过调用sleep()方法进入了TIMED_WAITING状态,这是阻塞状态的一种。在实际应用中,线程还可能因为其他原因(如等待I/O操作、等待锁等)进入阻塞或等待状态。
  5. 终止状态(TERMINATED):线程执行完run()方法中的代码后,进入终止状态。

线程的常用方法示例

线程的常用方法包括start()、run()、sleep()、join()等,它们在上述示例中已有体现。以下是这些方法的简要说明和示例:

  • start():启动线程,使线程从新建状态进入可运行状态。

    示例:thread.start();

  • run():线程启动后,JVM会调用线程的run()方法来执行线程的任务。

    注意:用户不应该直接调用线程的run()方法,而应该通过调用start()方法来启动线程。

  • sleep(long millis):使当前线程暂停执行指定的毫秒数,进入TIMED_WAITING状态。

    示例:Thread.sleep(1000);

  • join():等待当前线程终止。调用某个线程的join()方法会使当前线程阻塞,直到该线程终止。

    示例:thread.join();

  • yield():提示调度器当前线程愿意放弃当前的CPU时间片,让其他线程运行。但调度器可以忽略这个提示。

    示例:Thread.yield();

  • interrupt():中断线程。调用线程的interrupt()方法会设置该线程的中断状态为true,但不会立即停止线程的执行。线程需要定期检查自己的中断状态,并根据需要做出响应。

    示例:虽然示例中没有直接使用interrupt(),但在处理InterruptedException时通常会调用Thread.currentThread().interrupt()来保持中断状态。

通过理解线程的生命周期和常用方法,我们可以更好地编写和管理多线程程序,提高程序的并发性能和稳定性。

欢迎访问我的公众号或博客(点击查看头像信息)