Java线程生命周期与状态切换详解
一、线程生命周期概述
在 Java 中,线程是程序执行的最小单位,每个线程都有其自身的生命周期。线程的生命周期包含了一系列的状态,线程会在这些状态之间进行切换,直至最终结束。理解线程的生命周期和状态切换对于编写高效、稳定的多线程程序至关重要。
二、线程的六种状态
Java 中 Thread 类定义了一个枚举类型 State,它包含了线程的六种状态:
1. NEW(新建状态)
当创建一个 Thread 对象时,线程就处于新建状态。此时,线程仅仅是在 Java 虚拟机(JVM)中被分配了内存,还没有开始执行任何代码。
示例代码:
public class NewStateExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("线程正在执行");
});
// 此时线程处于 NEW 状态
System.out.println(thread.getState());
}
}
2. RUNNABLE(可运行状态)
当调用线程的 start() 方法后,线程进入可运行状态。处于可运行状态的线程可能正在 Java 虚拟机中执行,也可能在等待操作系统分配 CPU 时间片。
示例代码:
public class RunnableStateExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("线程正在执行");
});
thread.start();
// 此时线程处于 RUNNABLE 状态
System.out.println(thread.getState());
}
}
3. BLOCKED(阻塞状态)
当线程试图获取一个对象的锁,而该锁正被其他线程持有,线程就会进入阻塞状态。在阻塞状态下,线程不会占用 CPU 时间,直到它获取到锁。
示例代码:
public class BlockedStateExample {
private static final Object lock = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (lock) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock) {
System.out.println("线程 2 获取到锁");
}
});
thread1.start();
thread2.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 此时线程 2 处于 BLOCKED 状态
System.out.println(thread2.getState());
}
}
4. WAITING(等待状态)
当线程调用了 Object.wait()、Thread.join() 或 LockSupport.park() 方法后,线程会进入等待状态。处于等待状态的线程会无限期地等待,直到其他线程调用 Object.notify()、Object.notifyAll() 或 LockSupport.unpark() 方法来唤醒它。
示例代码:
public class WaitingStateExample {
private static final Object lock = new Object();
public static void main(String[] args) {
Thread thread = new Thread(() -> {
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 此时线程处于 WAITING 状态
System.out.println(thread.getState());
}
}
5. TIMED_WAITING(计时等待状态)
当线程调用了 Thread.sleep(long millis)、Object.wait(long timeout)、Thread.join(long millis) 或 LockSupport.parkNanos(long nanos)、LockSupport.parkUntil(long deadline) 方法后,线程会进入计时等待状态。在计时等待状态下,线程会等待指定的时间,时间一到就会自动唤醒。
示例代码:
public class TimedWaitingStateExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 此时线程处于 TIMED_WAITING 状态
System.out.println(thread.getState());
}
}
6. TERMINATED(终止状态)
当线程的 run() 方法执行完毕,或者线程因为异常而终止时,线程进入终止状态。处于终止状态的线程已经结束了其生命周期,不能再重新启动。
示例代码:
public class TerminatedStateExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("线程正在执行");
});
thread.start();
try {
// 等待线程执行完毕
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 此时线程处于 TERMINATED 状态
System.out.println(thread.getState());
}
}
三、线程状态切换
线程的状态会根据不同的操作和条件进行切换,下面是常见的状态切换情况:
1. NEW -> RUNNABLE
当调用线程的 start() 方法时,线程从新建状态切换到可运行状态。
2. RUNNABLE -> BLOCKED
当线程试图获取一个被其他线程持有的锁时,线程从可运行状态切换到阻塞状态。
3. RUNNABLE -> WAITING
当线程调用 Object.wait()、Thread.join() 或 LockSupport.park() 方法时,线程从可运行状态切换到等待状态。
4. RUNNABLE -> TIMED_WAITING
当线程调用 Thread.sleep(long millis)、Object.wait(long timeout)、Thread.join(long millis) 或 LockSupport.parkNanos(long nanos)、LockSupport.parkUntil(long deadline) 方法时,线程从可运行状态切换到计时等待状态。
5. BLOCKED -> RUNNABLE
当线程获取到之前被其他线程持有的锁时,线程从阻塞状态切换到可运行状态。
6. WAITING -> RUNNABLE
当其他线程调用 Object.notify()、Object.notifyAll() 或 LockSupport.unpark() 方法唤醒等待的线程时,线程从等待状态切换到可运行状态。
7. TIMED_WAITING -> RUNNABLE
当计时等待的时间到期时,线程从计时等待状态切换到可运行状态。
8. RUNNABLE -> TERMINATED
当线程的 run() 方法执行完毕,或者线程因为异常而终止时,线程从可运行状态切换到终止状态。
四、总结
Java 线程的生命周期和状态切换是多线程编程中的重要概念。了解线程的不同状态以及它们之间的切换条件,有助于我们更好地控制线程的执行流程,避免线程安全问题,从而编写出高效、稳定的多线程程序。在实际开发中,可以根据具体的需求,合理地使用线程的各种方法来实现线程状态的切换。
399

被折叠的 条评论
为什么被折叠?



