翻译文章 Life Cycle of a Thread in Java
线程的生命周期
java.lang.Thread类包含了一个静态枚举类Thread.State,它定义了线程的潜在状态,且同一时刻线程只能处在以下状态之一:
NEW: 尚未开始执行的新创建的线程RUNNABLE: 正在运行或准备执行,但正在等待资源分配BLOCKED: 等待获取监视器锁从而进入synchronized代码块或方法WAITING: 等待其它线程执行特定操作且没有时间限制TIMED_WAITING: 等待其它线程在指定时间内执行特定操作TERMINATED: 线程终止 上述所有的状态,都在下图中体现,下面我们会一一讨论这些状态。
NEW
NEW 表示一个已经被创建,但未启动的线程,线程将会保持这种状态,直到我们调用start()方法。
Runnable runnable = () -> System.out.println("");
Thread t = new Thread(runnable);
logger.info(t.getState().name());
代码会输出以下内容:
NEW
RUNNABLE
当我们创建了一个线程并调用了start()方法,线程状态由 NEW 变成 RUNNABLE, 处于RUNNABLE状态的线程有可能正在运行也可能准备执行,但在等待系统分配资源。
在多线程环境下,线程调度器分配时间片段给每个线程,获取时间片段的线程RUNNING一段时间后重回RUNNABLE状态,线程调度器再次分配时间片段给另一个RUNNABLE状态的线程.
Runnable runnable = () -> System.out.println("");
Thread t = new Thread(runnable);
t.start();
logger.info(t.getState().name());
代码会输出以下内容:
RUNNABLE
BLOCKED
线程处于BLOCKED状态时是没有资格运行的。当线程尝试获取synchronized持有的对象的监视器锁失败时会进入BLOCKED状态。
尝试模拟下该场景:
public class BlockedState {
static Logger logger = Logger.getLogger(BlockedState.class.getName());
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> loopMethod();
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
Thread.sleep(1000);
logger.info(t1.getState().name());
logger.info(t2.getState().name());
System.exit(0);
}
public synchronized static void loopMethod() {
while (true) {
// 死循环
// 导致 t1一直持有BlockedState.class 的锁处于RUNNABLE状态,
// 而t2因获取不到锁 始终处于BLOCKED状态
}
}
}
代码会输出以下内容:
RUNNABLE
BLOCKED
WAITING
依据JavaDocs,当调用以下任意一个方法时,线程会进入WAITING状态:
- object.wait()
- thread.join()
- LockSupport.park() 请注意在wait()和join()方法中,我们没有定义任何时间限制。
现在,我们来模拟一下这个状态:
public class WaitingState {
static Logger logger = Logger.getLogger(WaitingState.class.getName());
static Thread t1;
public static void main(String[] args) {
Runnable tas2 = () -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info(t1.getState().name());
};
Runnable task1 = () -> {
Thread t2 = new Thread(tas2);
t2.start();
try {
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
t1 = new Thread(task1);
t1.start();
}
}
解释下上述代码:
- 创建并启动了线程t1
- 线程t1中创建并启动了线程t2,
- 紧接着调用了
t2.join(), 这会将t1至于WAITING状态,知道t2完成执行 - 由于t1正在等待t2完成,所以我们在t2中打印了t1的状态。 此时代码会输出以下内容:
WAITING
TIMED_WAITING
处于TIMED_WAITING状态的线程,会等待另外一个线程在指定时间内执行特定操作
依据JavaDocs,当调用以下任意一个方法时,线程会进入TIMED_WAITING状态:
- thread.sleep(long millis)
- wait(int timeout) or wait(int timeout, int nanos)
- thread.join(long millis)
- LockSupport.parkNanos
- LockSupport.parkUnti
public class TimedWaitingState {
static Logger log = Logger.getLogger(TimedWaitingState.class.getName());
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Thread thread = new Thread(task);
thread.start();
Thread.sleep(1000);
log.info(thread.getState().name());
}
}
5秒后控制台输出如下:
TIMED_WAITING
TERMINATED
这是一个线程的死亡状态。线程完成或异常终止时,线程将处于TERMINATE状态
public class TerminatedState {
static Logger logger = Logger.getLogger(TerminatedState.class.getName());
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> System.out.println(""));
t.start();
// 给线程t足够的时间完成
Thread.sleep(1000);
logger.info(t.getState().name());
// 除了通过状态判断外,还可以通过isAlive()方法判断线程是否存活
Assert.assertFalse(t.isAlive());
}
}
TERMINATED