在Java中,线程的状态是随着线程的执行过程而变化的。Java线程主要有以下几种状态,以及它们之间的转换条件:
-
新建(NEW):线程被创建但尚未启动,即尚未调用
start()
方法。 -
就绪(RUNNABLE):线程已准备好运行,等待CPU分配时间片。这个状态包括了Java线程状态中的
RUNNABLE
和TIMED_WAITING
或WAITING
但已准备好再次运行的情况(等待的锁、条件变量等被满足)。 -
运行(RUNNING):线程正在执行中。请注意,Java API中没有直接表示“运行中”的状态,而是将运行中的线程视为
RUNNABLE
状态的一部分。 -
阻塞(BLOCKED):线程因为等待获取某个锁(监视器锁)而被阻塞。
-
等待(WAITING):线程等待另一个线程执行特定动作(如调用
Object
的notify()
或notifyAll()
方法)。线程在调用Object.wait()
、Thread.join()
、LockSupport.park()
等方法后,会进入此状态。 -
超时等待(TIMED_WAITING):与
WAITING
状态类似,但线程等待的时间是有限的。线程在调用带超时的Thread.sleep(long millis)
、Object.wait(long timeout)
、Thread.join(long millis)
等方法后,会进入此状态。 -
终止(TERMINATED):线程已执行完毕,或者因为异常或错误而提前终止。
下面是一个Java代码示例,展示了线程状态的转换:
public class ThreadStateExample {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {synchronized (ThreadStateExample.class) {System.out.println("线程尝试获取锁,进入BLOCKED状态(如果主线程已持有锁)");try {// 假设这里是为了演示而等待锁Thread.sleep(1000); // 实际上,这里不会改变线程状态为BLOCKED,因为没有竞争锁System.out.println("线程获取锁,准备执行,进入RUNNABLE状态");// 模拟一些操作Thread.sleep(1000);// 等待主线程通知System.out.println("线程等待通知,进入WAITING状态");try {ThreadStateExample.class.wait(); // 这里会真正让线程进入WAITING状态} catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println("线程被唤醒,再次进入RUNNABLE状态");} catch (InterruptedException e) {Thread.currentThread().interrupt();}}});// 启动线程thread.start();// 主线程持有锁,使子线程阻塞synchronized (ThreadStateExample.class) {System.out.println("主线程持有锁,子线程将尝试获取锁");Thread.sleep(500); // 确保子线程开始执行并尝试获取锁}// 让子线程执行一段时间Thread.sleep(2000);// 唤醒子线程(实际上在这个例子中,我们不需要显式唤醒,因为子线程在等待后会自动尝试再次获取锁)// 但为了演示,我们再次获取锁并通知synchronized (ThreadStateExample.class) {System.out.println("主线程通知子线程");ThreadStateExample.class.notify();}// 等待子线程完成thread.join();System.out.println("线程执行完毕,进入TERMINATED状态");}
}
注意:
- 示例中的
Thread.sleep(1000);
在同步块内只是为了模拟操作时间,并不直接导致线程状态的变化(除了让出CPU时间片)。 synchronized
块和wait()
/notify()
方法用于演示线程之间的交互和状态转换。- 在实际编程中,线程的状态和转换更多地依赖于具体的业务逻辑和并发控制需求。