Java 线程状态转换详解

在 Java 编程中,线程是实现并发的关键组成部分。理解 Java 线程的状态及其转换有助于更好地管理和优化线程的使用。Java 线程主要处于以下几种状态:新建(New)、运行(Runnable)、阻塞(Blocked)、等待(Waiting)、定时等待(Timed Waiting)和死亡(Terminated)。下面,我们将逐一分析这些状态及相应的代码示例。

线程状态概述

  1. 新建(New):线程创建后尚未调用 start() 方法处于这种状态。
  2. 运行(Runnable):线程正在运行或者在 Java 虚拟机中处于准备运行的状态。
  3. 阻塞(Blocked):线程被阻塞,等待获取对象锁。
  4. 等待(Waiting):线程在等待另一个线程执行特定操作而进入的状态,此时线程不会占用 CPU。
  5. 定时等待(Timed Waiting):线程在等待特定时间后自动返回的状态,例如调用 sleep()join(long millis) 方法。
  6. 死亡(Terminated):线程执行完毕或由于异常终止。

以下是一个简化的线程状态转换图示:

新建 -> 运行 <-> 阻塞
            |
            v
          等待
            |
            v
        定时等待 -> 运行

线程状态转换示例代码

新建状态示例

首先,我们来创建一个新线程,处于新建状态。示例代码如下:

class MyThread extends Thread {
    public void run() {
        System.out.println("线程正在运行...");
    }
}

public class ThreadExample {
    public static void main(String[] args) {
        MyThread thread = new MyThread(); // 线程处于新建状态
        System.out.println("线程状态: " + thread.getState());
        thread.start(); // 启动线程
    }
}

在以上代码中,调用 thread.start() 后,线程的状态将从新建状态转变为运行状态。

运行状态示例

当线程开始运行时,它就进入了运行状态。在此状态下,线程可以被操作系统调度运行。

阻塞状态示例

当一个线程尝试获取一个被其他线程持有的锁时,会进入阻塞状态。例如:

class BlockedThread extends Thread {
    public void run() {
        synchronized (this) {
            while (true) {
                System.out.println("线程在运行...");
            }
        }
    }
}

public class BlockedExample {
    public static void main(String[] args) {
        BlockedThread thread1 = new BlockedThread();
        BlockedThread thread2 = new BlockedThread();
        
        thread1.start();
        thread2.start();
        
        synchronized (thread1) {
            // thread2 试图获得 thread1 的锁,进入阻塞状态
            thread2.join();
        }
    }
}

在这个例子中,thread2 尝试获得 thread1 的锁,在此过程中进入阻塞状态。

等待状态示例

线程可以在等待状态下,直到其他线程调用 notify()notifyAll()。以下是实现示例:

class WaitingThread extends Thread {
    public void run() {
        synchronized (this) {
            try {
                System.out.println("线程进入等待状态...");
                wait(); // 进入等待状态
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("线程被唤醒...");
    }
}

public class WaitingExample {
    public static void main(String[] args) throws InterruptedException {
        WaitingThread thread = new WaitingThread();
        thread.start();

        // 主线程等待一段时间,然后唤醒 t1
        Thread.sleep(1000);
        synchronized (thread) {
            thread.notify(); // 唤醒线程
        }
    }
}

定时等待状态示例

线程在调用 sleep() 方法后,会进入定时等待状态。在指定的时间后,线程会自动返回运行状态:

class SleepThread extends Thread {
    public void run() {
        try {
            System.out.println("线程将进入睡眠状态...");
            Thread.sleep(2000); // 进入定时等待状态
            System.out.println("线程恢复运行...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class SleepExample {
    public static void main(String[] args) {
        SleepThread thread = new SleepThread();
        thread.start();
    }
}

结论

我们通过具体示例详细探讨了 Java 线程的各个状态及其转换。理解这些状态的转换规则,可以帮助我们更好地控制线程的生命周期,从而提高程序的并发性能和稳定性。在实际开发中,合理使用线程状态转换能够优化程序的效率和响应能力。希望本文能帮助读者更深入地理解 Java 线程的运作机制。