1、线程状态
Java中的线程状态被定义在了java.lang.Thread.State
中,State
枚举类的源码如下:
public class Thread {
public enum State {
/* 新建 */
NEW ,
/* 可运行状态 */
RUNNABLE ,
/* 阻塞状态 */
BLOCKED ,
/* 无限等待状态 */
WAITING ,
/* 计时等待 */
TIMED_WAITING ,
/* 终止 */
TERMINATED;
}
// 获取当前线程的状态
public State getState() {
return jdk.internal.misc.VM.toThreadState(threadStatus);
}
}
通过源码我们可以看到Java中的线程存在6种状态,每种线程状态的含义如下
线程状态 | 具体含义 |
---|---|
NEW | 一个尚未启动的线程的状态。也称之为初始状态、开始状态。线程刚被创建,但是并未启动。还没调用start方法。MyThread t = new MyThread()只有线程象,没有线程特征。 |
RUNNABLE | 当我们调用线程对象的start方法,那么此时线程对象进入了RUNNABLE状态。那么此时才是真正的在JVM进程中创建了一个线程,线程一经启动并不是立即得到执行,线程的运行与否要听令与CPU的调度,那么我们把这个中间状态称之为可执行状态(RUNNABLE)也就是说它具备执行的资格,但是并没有真正的执行起来而是在等待CPU的度。 |
BLOCKED | 当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。 |
WAITING | 一个正在等待的线程的状态。也称之为等待状态。造成线程等待的原因有两种,分别是调用Object.wait()、join()方法。处于等待状态的线程,正在等待其他线程去执行一个特定的操作。例如:因为wait()而等待的线程正在等待另一个线程去调用notify()或notifyAll();一个因为join()而等待的线程正在等待另一个线程结束。 |
TIMED_WAITING | 一个在限定时间内等待的线程的状态。也称之为限时等待状态。造成线程限时等待状态的原因有三种,分别是:Thread.sleep(long),Object.wait(long)、join(long)。 |
TERMINATED | 一个完全运行完成的线程的状态。也称之为终止状态、结束状态 |
各个状态的转换,如下图所示:
2、代码示例
需求:编写一段代码,演示TIME_WAITING
的状态转换;
为了简化我们的开发,本次我们使用匿名内部类结合lambda
表达式的方式使用多线程。
代码实现:
public class ThreadStateDemo01 {
public static void main(String[] args) throws InterruptedException {
//定义一个内部线程
Thread thread = new Thread(() -> {
System.out.println("次2.执行thread.start()之后,["+Thread.currentThread().getName()+"]线程的状态:" + Thread.currentThread().getState());
try {
//休眠100毫秒
Thread.sleep(100);
} catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("次4.执行Thread.sleep(long)完成之后,["+Thread.currentThread().getName()+"]线程的状态:" + Thread.currentThread().getState());
},"子线程");
//获取start()之前的状态
System.out.println("次1.通过new初始化一个线程,但是还没有start()之前,["+thread.getName()+"]线程的状态:" + thread.getState());
//启动线程,此时thread还没开始执行,执行权仍在main主线程手里
thread.start();
//main主线程休眠50毫秒,从main主线程开始休眠那一刻起,cpu被thread抢走并执行完次2后休眠100毫秒
Thread.sleep(50);
//从main线程开始休眠50毫秒开始,thread也需要休眠100毫秒,所以当main线程休眠到50毫秒瞬间,thread还需要休眠50毫秒,所以thread仍处于sleep状态
System.out.println("次3.执行Thread.sleep(long)时,["+thread.getName()+"]线程的状态:" + thread.getState());
//此时main线程再休眠100毫秒,thread还需要再休眠50毫秒,当main线程休眠到50毫秒时,thread已经休眠完毕,此时thread重新抢夺cpu执行权,输出次4,完成次线程,所以当main线程休眠完后,thread肯定已经执行完毕;
Thread.sleep(100);
System.out.println("次5.线程执行完毕之后,["+thread.getName()+"]线程的状态:" + thread.getState() + "\n");
}
}
控制台输出:
次1.通过new初始化一个线程,但是还没有start()之前,[子线程]线程的状态:NEW
次2.执行thread.start()之后,[子线程]线程的状态:RUNNABLE
次3.执行Thread.sleep(long)时,[子线程]线程的状态:TIMED_WAITING
次4.执行Thread.sleep(long)完成之后,[子线程]线程的状态:RUNNABLE
次5.线程执行完毕之后,[子线程]线程的状态:TERMINATED
- 通过控制台输出可以看出,程序在运行过程中,首先输出次1,此时次线程
thread
只是通过new
初始化了,但还没start
,所以thread
的状态为NEW
; - 然后通过
thread.start()
启动次线程,此时thread
还没开始执行,执行权仍在main
主线程手里。 - 接着
main
主线程休眠50毫秒,从main
主线程开始休眠那一刻起,cpu被thread
抢走并执行完次2后休眠100毫秒,此时因为thread
已经启动,所以状态为RUNNABLE
; - 输出次3,因为从
main
线程开始休眠50毫秒开始,thread
也需要休眠100毫秒,所以当main
线程休眠到50毫秒瞬间,thread
还需要休眠50毫秒,所以thread
仍处于sleep
状态,此时次线程状态为:TIMED_WAITING
; - 此时
main
线程再休眠100毫秒,thread
还需要再休眠50毫秒,当main
线程休眠到50毫秒时,thread
已经休眠完毕,此时thread
重新抢夺cpu执行权,输出次4,完成次线程,所以当main
线程休眠完后,thread
肯定已经执行完毕; - 最后输出次5,这时次线程早已执行完毕,所以状态为
TERMINATED
;
如果觉得结果还不够直观,我们可以尝试着更改主线程的休眠时间,再来测试一下;
...
Thread.sleep(50);
System.out.println("次3.执行Thread.sleep(long)时,["+thread.getName()+"]线程的状态:" + thread.getState());
//在这里把原本休眠100毫秒改成40毫秒
Thread.sleep(40);
System.out.println("次5.线程执行完毕之后,["+thread.getName()+"]线程的状态:" + thread.getState() + "\n");
...
此时再观察输出结果
次1.通过new初始化一个线程,但是还没有start()之前,[子线程]线程的状态:NEW
次2.执行thread.start()之后,[子线程]线程的状态:RUNNABLE
次3.执行Thread.sleep(long)时,[子线程]线程的状态:TIMED_WAITING
次5.线程执行完毕之后,[子线程]线程的状态:TIMED_WAITING
次4.执行Thread.sleep(long)完成之后,[子线程]线程的状态:RUNNABLE
会发现,在main
主线程第二次休眠完时(40毫秒),次线程的100毫秒还没休眠完,所以次5会比次4先输出,而且此时次线程状态为TIMED_WAITING
,当次线程100毫秒休眠完后,输出次4,此时此线程还没走完,所以线程状态为RUNNABLE
;
至此,示例结束;