• 作者:老汪软件技巧
  • 发表时间:2024-09-14 11:02
  • 浏览量:

在 Java 中,Thread 类定义了 6 种线程状态,这些状态描述了一个线程的生命周期中的不同阶段。理解这些状态对于编写多线程程序、调试和优化性能非常重要。

本文将详细介绍这六种线程状态,并通过示例代码演示每种状态的行为。此外,还将讨论一些常见的线程方法(如 Thread.sleep() 和 Object.wait())是如何影响线程状态的。

1. 线程状态的定义

Thread.State 是 Java 中枚举类型 Thread 的内部类,用于描述线程的六种状态。定义如下:

public enum State {
    // 新建状态:线程对象已经创建,但未调用 start() 方法
    NEW,
    
    // 运行状态:线程已经调用 start() 方法,正在运行中
    RUNNABLE,
    
    // 阻塞状态:线程试图获取锁但失败,正在等待锁释放
    BLOCKED,
    
    // 无限期等待:线程等待某个条件的发生,例如调用了 Object.wait() 方法且没有超时设置
    WAITING,
    
    // 有限期等待:线程在一定时间内等待条件的发生,例如调用了 Thread.sleep(n) 或 Object.wait(n)
    TIMED_WAITING,
    
    // 终止状态:线程执行完 run() 方法或因异常退出,线程结束
    TERMINATED;
}

2. 各种状态演示2.1 NEW 状态

当一个线程被创建时,它处于 NEW 状态。此时线程还没有开始执行,调用 start() 方法后会进入 RUNNABLE 状态。

Thread thread = new Thread(() -> {
    System.out.println("Thread is running");
});
System.out.println(thread.getState());  // 输出:NEW

2.2 RUNNABLE 状态

当线程调用 start() 方法后,它进入 RUNNABLE 状态。此时,线程正在 Java 虚拟机中运行,等待 CPU 时间片的分配。

Thread thread = new Thread(() -> {
    while (true) {
        // 模拟线程正在运行
    }
});
thread.start();
System.out.println(thread.getState());  // 输出:RUNNABLE

注意:RUNNABLE 并不一定意味着线程正在运行,而是可能正在等待操作系统分配的 CPU 时间。

2.3 BLOCKED 状态

当线程试图获取一个锁时,如果该锁已经被其他线程占用,线程将进入 BLOCKED 状态,等待锁的释放。

class SyncClass {
    public synchronized void syncMethod() {
        while (true) {
            // 模拟线程占用锁
        }
    }
}
SyncClass syncClass = new SyncClass();
Thread thread1 = new Thread(() -> syncClass.syncMethod());
Thread thread2 = new Thread(() -> syncClass.syncMethod());
thread1.start();
thread2.start();
Thread.sleep(1000);  // 让 thread1 获得锁
System.out.println(thread2.getState());  // 输出:BLOCKED

2.4 WAITING 状态

线程在 WAITING 状态下,会一直等待其他线程的通知或者中断。这种状态通常通过调用没有超时的 Object.wait()、Thread.join()、或 LockSupport.park() 等方法来进入。

Object lock = new Object();
Thread thread = new Thread(() -> {
    synchronized (lock) {
        try {
            lock.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});
thread.start();
Thread.sleep(1000);  // 等待线程进入 wait 状态
System.out.println(thread.getState());  // 输出:WAITING

2.5 TIMED_WAITING 状态

线程在 TIMED_WAITING 状态下,会在有限的时间内等待其他线程的通知或中断。线程调用 Thread.sleep(n)、Object.wait(n)、或 Thread.join(n) 等带有超时参数的方法时会进入此状态。

2.5.1 Thread.sleep(n)

Thread.sleep(n) 方法将使当前线程休眠 n 毫秒,这期间线程进入 TIMED_WAITING 状态。

Thread thread = new Thread(() -> {
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});
thread.start();
Thread.sleep(1000);  // 在 thread 睡眠期间
System.out.println(thread.getState());  // 输出:TIMED_WAITING

2.5.2 Object.wait(n)

类似于 Thread.sleep(),Object.wait(n) 方法也会使线程在等待通知时,进入 TIMED_WAITING 状态,不过这里的 wait() 是与锁相关联的。

Object lock = new Object();
Thread thread = new Thread(() -> {
    synchronized (lock) {
        try {
            lock.wait(2000);  // 等待 2 秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});
thread.start();
Thread.sleep(1000);
System.out.println(thread.getState());  // 输出:TIMED_WAITING

_线程状态java_java线程状态有哪几种

2.6 TERMINATED 状态

当线程执行完 run() 方法或抛出未捕获的异常时,线程进入 TERMINATED 状态。此时线程生命周期结束,无法再次启动。

示例代码:

Thread thread = new Thread(() -> {
    System.out.println("Thread finished");
});
thread.start();
thread.join();  // 等待线程执行完毕
System.out.println(thread.getState());  // 输出:TERMINATED

3. 常见问题解答3.1 Thread.sleep(0) 会做什么?

Thread.sleep(0) 并不会使线程进入 TIMED_WAITING 状态,因为它不会真正休眠。实际上,它只是一个提示给线程调度器,允许其他线程获取 CPU 时间。如果没有其他线程需要执行,该线程可能会继续运行。

3.2 Object.wait(0) 和 Object.wait() 的区别

Object.wait(0) 和 Object.wait() 的效果相同:都使线程进入 WAITING 状态,并等待其他线程调用 notify() 或 notifyAll() 使其苏醒。参数 0 表示无限期等待。

3.3 什么状态会释放cpu资源?3.3.1 WAITING

线程处于 无限期等待 状态时,会释放 CPU 资源。线程调用以下方法进入 WAITING 状态:

此时线程会暂停执行,直到其他线程通过 notify()、notifyAll()、unpark() 或者 join() 目标线程结束来唤醒它。

3.3.2 TIMED_WAITING

线程进入 有超时的等待 状态时,同样会释放 CPU 资源。线程调用以下方法进入 TIMED_WAITING 状态:

线程会等待指定时间,或者被唤醒后继续执行。

3.3.3 BLOCKED

线程进入 阻塞 状态时,会等待同步锁的释放,并释放 CPU 资源。当其他线程释放该锁时,BLOCKED 状态的线程才有机会获取锁并进入 RUNNABLE 状态。

3.3.4 TERMINATED

线程执行完毕或抛出未捕获的异常进入 终止状态 时,它将不再占用 CPU 资源,因为线程生命周期已经结束。

3.4 什么状态会释放Synchronized锁资源?3.4.1 WAITING 和 TIMED_WAITING

当线程调用 Object.wait() 或 Object.wait(n) 进入等待状态时,线程会释放当前持有的同步锁。这是因为 wait() 方法在内部会使线程释放锁,进入等待队列,直到通过 notify() 或 notifyAll() 被唤醒。

3.4.3 TERMINATED

线程执行完毕或抛出未捕获异常进入 TERMINATED 状态时,会自动释放它持有的所有同步锁。

4. 线程状态的转换图

下图展示了 Java 线程的状态流转过程:

5. 总结

Java 中的线程状态为我们提供了分析线程行为的重要工具。在实际编程中,理解每个状态的意义以及如何触发状态变化,可以帮助我们编写更高效、可靠的多线程应用程序。