在上一章节中我们了解到线程怎么创建和执行。在实际开发过程中多线程是很容易出现问题的,一不小心可能会导致死锁从而引起整个系统崩溃。只有对线程的整个运行过程比较了解才能及时地去找到问题在哪。不知道大家有没有想过下面几个问题,
- 一共有哪些线程状态呢?
- 为什么要了解这些线程状态呢?
- 这些状态怎么查看呢?
我相信带着问题去学习是一种更高效的学习方式。接下来我会给小伙伴们一一找到答案。
上图是综合了线程一般状态和JVM中线程状态,其中红框等待timed_waiting、 等待waiting、阻塞blocked都是JVM的线程状态,JVM线程状态在JDK中有一个枚举类java.lang.Thread.State表示:
public enum State {
/**
* 线程还没有启动时的状态
*/
NEW,
/**
* 可运行状态。
*/
RUNNABLE,
/**
* 进入synchronized同步代码块
*/
BLOCKED,
/**
* 执行以下方法进入WAITING状态
* Object.wait
* Thread.join
* LockSupport.park
*/
WAITING,
/**
* 执行以下带有时间的方法进入TIMED_WAITING状态
* Thread.sleep(long)
* Object.wait(long)
* Thread.join(long)
* LockSupport.parkNanos
* LockSupport.parkUntil
*/
TIMED_WAITING,
/**
* 终止或者消亡状态
*/
TERMINATED;
}
下面我们通过代码和jstack命令演示下不同方法调用对应的不同线程状态
1. sleep(long)会使线程进入timed_waiting状态
/**
* 调用sleep(long)线程处于timed_waiting状态
*
* @author jinglei
* @date 2020/8/21 13:09
*/
public class TimedWaitingBySleep {
public static void main(String[] args) {
//1.sleep
Thread sleepThread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("调用sleep()之后线程处于timed_waiting状态");
try {
Thread.currentThread().sleep(50000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
sleepThread.setName("mythread-sleep");
//启动线程
sleepThread.start();
}
}
运行程序,然后通过jps命令找到对应的进程id,再用jstack processId > D:/test/sleepTimedWaiting.log把线程堆栈输出到文件
文件内容如下图
可以看出mythread-sleep这个线程处于java.lang.Thread.State: TIMED_WAITING (sleeping)这个状态。
通过jstack查看线程堆栈的这种方法要学会使用,以后排查问题可能会遇到,比如网上经典的面试题“生产环境出现了cpu100%,你怎么排查”这时候jstack就派上大用场了。
2. wait(long)会使线程进入timed_waiting状态
/**
* 调用wait(long)线程处于timed_waiting状态
*
* @author jinglei
* @date 2020/8/21 13:09
*/
public class TimedWaitingByWait {
private static Object lock = new Object();
public static void main(String[] args) {
//2.wait(long)
Thread waitLongThread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("wait(long)之后线程处于timed_waiting状态");
synchronized (lock){
try {
lock.wait(50000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println();
}
}
});
waitLongThread.setName("mythread-waitLong");
//启动线程
waitLongThread.start();
}
}
通过上面的方法查看到的线程状态如下图
3.Thread.join(long)会使线程进入timed_waiting状态
/**
* 调用join(long)线程处于timed_waiting状态
*
* @author jinglei
* @date 2020/8/21 13:09
*/
public class TimedWaitingByJoin {
public static void main(String[] args) {
//join(long)
Thread joinLongThread = new Thread(new Runnable() {
@Override
public void run() {
while(true){
// System.out.println();
}
}
});
joinLongThread.setName("mythread-joinLong");
//启动线程
joinLongThread.start();
System.out.println("join(long)之后线程处于timed_waiting状态");
try {
joinLongThread.join(15000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main-----------");
while(true){
}
}
}
一定要注意先调用start()方法启动线程,再调用join()方法使调用线程加入等待队列。
然后通过jstack输出线程堆栈
堆栈日志如下:
可以看出在执行了joinLongThread.join(15000)之后,使主线程main进入了等待timed_waiting,等15秒之后主线程恢复执行,输出"main-----------",此时再做一次线程堆栈日志
main线程恢复执行后的线程堆栈内容如下:
可以看出main线程此时处于Runnable状态,实际上主线程正在执行空循环
while(true){
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。