线程在操作系统中其自身是有一个自己的状态的,例如:线程还没运行,线程已结束,线程正在运行,线程堵塞等一系列状态,而Java Thread其实是对操作系统中线程的封装,把这些状态又进一步的精细化。那么如何查看线程的状态呢?这些状态分别用什么表示呢?,每个新状态代表的含义又是什么呢?
带着这些问题,让我们来进入本篇的学习!
目录
Java获取线程状态:调用getState方法,返回的是一个线程状态的枚举变量
线程状态的分类
-
NEW
NEW 表示线程在操作系统中还没被创建出来,只是得到了一个线程实例对象,在启动线程之前获取的一个线程状态
上篇文章我们也介绍了,new了一个Thread 并不意味着创建了一个线程,只是获取到了一个线程对象,而真正创建线程的调用的start()方法,参考上篇文章,直接调用run方法和调用statrt方法的区别就能很好的体现
public class Test{
public static void main(String[] args){
Thread t = new Thread(() -> {
System.out.println("hello world");
});
//此时线程t的实例已经创建好了,但是线程还没正式创建
System.out.println(t.getState()); //此时获取 t 线程的状态 就是NEW状态了
t.start() //调用此处才会真正的创建线程
}
}
上述代码就表明,线程并没有开始执行,那么此时我们获取到的线程状态就为NEW状态
-
TERMINATED
线程执行结束,但是线程对象还在
展示代码:
public class ThreadDemo9 {
public static void main(String[] args) {
Thread t = new Thread(() -> {
System.out.println("hello world");
});
t.start(); //创建并启动线程
try {
Thread.sleep(1000); //主线程休眠1000毫秒,以确保t线程执行完毕
} catch (InterruptedException e) {
e.printStackTrace();
}
//获取线程状态并打印
System.out.println(t.getState());
}
}
-
RUNNABLE
表示当前线程处于就绪态。
就绪态分为两种情况:
1. 线程正在CPU执行
2. 线程已经准备好了,正在排队,随时可以上CPU执行
//RUNNABLE状态:表示该线程正在执行或者已经准备好了,随时可以开始执行
public static void main(String[] args) {
Thread t = new Thread(() -> {
while(true){
//此处不写打印方法
//因为print操作是一个加了锁(synchronized修饰)的方法。
//只会同时打印一个
}
});
t.start();
System.out.println(t.getState());
}
上述代码 t 线程一直在执行,那么 t 线程的状态就为RUNNABLE(就绪态)
-
TIMED_WAITING(限时等待)
限时等待: 表示线程正在休眠,一段时间后恢复的状态
注意区分与WAITING不同点
TIMED_WAITING 表示的是一定时间内休眠并不是死等,例如sleep或者带参数的join。
如果直接调用join方法,不设置参数,那么此时线程一定是死等直到等待的线程结束,那么此时就不是TIMED_WAITING状态了,而是WAITING状态,所以注意和WAITING状态进行区分
public static void main(String[] args) { Thread t1 = new Thread(() -> { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("hello world"); }); //执行线程t1 t1.start(); Thread t2 = new Thread(() -> { //此时线程 t2 等待线程 t1 执行 等待5000毫秒 try { t1.join(5000); } catch (InterruptedException e) { e.printStackTrace(); } }); //执行线程t2 t2.start(); //休眠一段时间让线程 t2 进入休眠 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(t2.getState()); }
上述代码意思为:t2 线程等待 t1 线程 5000毫秒,在此期间,我们查看 t2 线程的状态就是TIMED_WAITING(限时等待)了。
如果我们 t2 线程中的 join方法不设置参数,那么此时就为死等 t1 线程,那么此时就为WAITING状态
-
BLOCKED
等待锁出现的状态:线程因为等待锁而堵塞
比如某一操作的代码块加锁了,此时有两个线程(t1,t2)去执行该代码块,t1线程先抢到锁,进而执行代码,那么此时t2 线程则需要堵塞去等待 t1解锁,然后在进行加锁执行操作,此时 t2 在等待 t1解锁的这个时期内,t2 的状态就为BLOCKED。
synchronized public static void fun(int x){ try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(x); } public static void main(String[] args) { Thread t1 = new Thread(() -> { fun(1); }); t1.start(); Thread t2 = new Thread(() -> { fun(2); }); t2.start(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(t2.getState()); }
此时上述代码,在 t1线程 执行加锁代码的时候,t2线程来到锁外等待,那么 t2 线程此时的状态就为 BLOCKED
-
WAITING
堵塞等待状态:一个线程堵塞等待另一个线程,直到一个被等待的线程结束,等待的线程才能进行执行,那么此时进行堵塞等待的线程就是出于WAITING状态
注意与TIMED_WAITING进行区分
常见方法:wait方法,join(不带参数)等这些进入死等的方法都会使线程线程进入该状态
线程状态的转移
我们线程的执行是会发生变化,那么我们线程的状态也自然会根据实际情况发生变化
从new线程实例对象 —> 线程执行 —> 线程执行完毕 —> ,其中这条状态主线上会有一些其他的状态:因为各种原因触发的线程堵塞和休眠
那么让我们来进一步分析一下线程的状态之间的转移
根据线程执行的主线状态:NEW —> RUNNABLE —> TERMINATED;线程执行期间遇到不同的休眠堵塞情况则进入不同的状态:等待锁则为BLOCKED状态,限时等待则TIME_WAITING状态,必须等到其他线程执行完毕的等待则是WAITING状态
本篇文章介绍到这里就结束了,希望各位读者都能有所收获!
喜欢本篇文章的小伙伴能不能留下你的三连呢,在此感谢!!!
我们下期再见!