目录
- 一、简介
- 二、线程状态
- 1、新建状态(New)
- 2、运行状态(Runnable)
- 3、阻塞状态(Blocked/Waiting/TimeWaiting)
- (1)被阻塞状态(Blocked)
- (2)等待状态(Waiting)
- (3)超时等待状态(TimeWaiting)
- 4、终止状态(Terminated)
- 三、总结
- 四、示例
一、简介
线程的六种状态:
New
- 新建状态;Runnable
- 运行状态;Blocked
- 被阻塞状态;Waiting
- 等待状态;TimeWaiting
- 超时等待状态;Terminated
- 终止状态;
线程状态之间的转换图:
二、线程状态
1、新建状态(New)
New
:线程被创建,但尚未启动的状态。
当我们用 new Thread();
新建一个线程时,如果线程没有开始执行 start()
方法,所以没有开始执行 run()
方法里面的代码,那么线程此时的状态就是 New
。而一旦线程调用了 start()
方法,它的状态就会从 New
变成 Runnable
。
2、运行状态(Runnable)
Java
中的 Runnable
状态对应操作系统线程状态中的两种状态:
Runnable
- 运行状态;Ready
- 就绪状态,正在等待被分配CPU
资源;
如果一个正在运行的线程是 Runnable
状态,当它运行到任务的一半时,执行该线程的 CPU
被调度去做其他事情,导致该线程暂时不运行,它的状态依然是 Runnable
,因为它有可能随时被调度回来继续执行任务。
3、阻塞状态(Blocked/Waiting/TimeWaiting)
在 Java
中阻塞状态包括三种状态:
-
Blocked
- 被阻塞状态; -
Waiting
- 等待状态; -
TimeWaiting
- 超时等待状态;
(1)被阻塞状态(Blocked)
线程 Blocked
状态的转换:
-
Runnable 状态进入 Blocked 状态
:进入synchronized
保护的代码(包括:synchronized代码块
和synchronized方法
)时没有抢到monitor
锁。 -
Blocked 状态回到 Runnable 状态
:处于Blocked
的线程抢到monitor
锁。
(2)等待状态(Waiting)
线程进入 Waiting
状态有以下三种可能:
-
run()
方法中调用Object.wait()
; -
run()
方法中调用Thread.join()
; -
run()
方法中调用LockSupport.park()
;
前面强调了 Blocked
是针对 synchronized monitor
锁,可是在 Java
中还有很多其他锁,比如 ReentrantLock
,如果线程在获取这种锁时,没有抢到该锁,就会进入 Waiting
状态,因为本质上它执行了 LockSupport.park()
方法,所以会进入 Waiting
状态,同样,Object.wait()
和 Thread.join()
也会让线程进入 Waiting
状态。
Blocked
与 Waiting
的区别:
-
Blocked
在等待其他线程释放monitor
锁; -
Waiting
在等待某个条件,比如join
的线程执行完毕或者是notify()
/notifyAll()
;
Waiting
状态流转到其他状态比较特殊,因为 Waiting
是不限时的,也就是说无论过了多长时间它都不会主动恢复。
线程 Waiting
状态的转换:
-
当执行了
LockSupport.unpark()
,或者join()
的线程运行结束,或者被中断时,线程才会从Waiting
状态进入Runnable
状态; -
其他线程如果调用了
notify()
或notifyAll()
来唤醒它,线程会直接进入Blocked
状态(因为唤醒Waiting
线程的线程如果调用了notify()
或notifyAll()
,要求首先要持有该monitor
锁,所以处于Waiting
状态的线程被唤醒时拿不到该锁,就会进入Blocked
状态,直到执行了notify()
/notifyAll()
的唤醒它的线程执行完毕并释放了monitor
锁,才可能轮到它去抢夺这把锁,如果它能抢到,就会从Blocked
状态回到Runnable
状态);
(3)超时等待状态(TimeWaiting)
TimeWaiting
与 Waiting
状态非常相似,区别仅仅在于有没有超时限制,TimeWaiting
会等待超时,由系统自动唤醒,或者在超时前被唤醒信号唤醒。
线程进入 TimeWaiting
状态有以下几种可能:
-
run()
方法中调用Thread.sleep(sleeptime)
; -
run()
方法中调用Object.wait(timeout)
; -
run()
方法中调用Thread.join(timeout)
; -
run()
方法中调用LockSupport.parkNanos(timeout)
; -
run()
方法中调用LockSupport.parkUntil(timeout)
;
线程 TimeWaiting
状态的转换:
-
如果
TimeWaiting
超时时间未超时,当其他线程调用了notify()
或notifyAll()
,TimeWaiting
状态的线程会先进入Blocked
状态,然后抢夺monitor
锁成功后,再会进入到Runnable
状态,此种情况下TimeWaiting
与Waiting
状态一样的; -
如果
TimeWaiting
超时时间超时,且能直接获取到锁 / join的线程运行结束 / 被中断 / 调用了LockSupport.unpark(),会直接恢复到Runnable
状态;
4、终止状态(Terminated)
进入终止状态的两种可能:
-
线程正常退出
:run()
方法执行完毕; -
线程意外终止
:出现一个没有捕获的异常,终止了run()
方法;
三、总结
线程状态总结:
-
new Thread()
,但没有调用start()
方法,线程处于New
状态; -
new Thread()
,且调用了start()
方法,线程处于Runnable
状态; -
new Thread()
,且调用了start()
方法,run()
方法中调用了thread.join()
或object.wait()
方法,线程处于Waiting
状态; -
new Thread()
,且调用了start()
方法,run()
方法中调用了Thread.sleep(sleeptime)
方法,线程处于TimeWaiting
状态; -
new Thread()
,且调用了start()
方法,run()
方法中获取monitor
锁,且没有获取到,线程处于Blocked
状态; -
new Thread()
,且调用了start()
方法,run()
方法正常执行完毕或抛出未捕获的异常而结束,线程处于Terminated
状态;
线程转换注意事项:
-
线程状态是需要按照箭头方向流转
:比如线程从New
状态是不可以直接进入Blocked
状态的,它需要先经历Runnable
状态; -
线程生命周期不可逆
:一旦进入Runnable
状态就不能回到New
状态,一旦终止就不可能再有任何状态变化,所以一个线程只能有一次New
和Terminated
状态,只有处于中间状态才可以相互转换;
四、示例
六种线程状态示例:
package com.cw.tsb.test;
/**
* @author Davis
* @Date 2022-12-29 11:27 上午
*/
public class ThreadStateTest {
public static void main(String[] args) {
threadState();
}
private static void threadState(){
Thread t1 = new Thread("t1") {
@Override
public void run() {
System.out.println("running...");
}
};
Thread t2 = new Thread("t2") {
@Override
public void run() {
while(true) { // runnable
}
}
};
t2.start();
Thread t3 = new Thread("t3") {
@Override
public void run() {
System.out.println("running...");
}
};
t3.start();
Thread t4 = new Thread("t4") {
@Override
public void run() {
synchronized (ThreadStateTest.class) {
try {
Thread.sleep(1000000); // timed_waiting
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t4.start();
Thread t5 = new Thread("t5") {
@Override
public void run() {
try {
t2.join(); // waiting
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t5.start();
Thread t6 = new Thread("t6") {
@Override
public void run() {
synchronized (ThreadStateTest.class) { // blocked
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t6.start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1 state : " + t1.getState());
System.out.println("t2 state : " + t2.getState());
System.out.println("t3 state : " + t3.getState());
System.out.println("t4 state : " + t4.getState());
System.out.println("t5 state : " + t5.getState());
System.out.println("t6 state : " + t6.getState());
}
}
输出结果:
running...
t1 state : NEW
t2 state : RUNNABLE
t3 state : TERMINATED
t4 state : TIMED_WAITING
t5 state : WAITING
t6 state : BLOCKED