参考:https://my.oschina.net/goldenshaw?tab=newest&catalogId=3277710
1 线程状态
Java
中的线程一共有6
种状态。
在某个时刻,Java
中的线程只能处于这6
种状态中的一种。
1.1 线程状态的定义
Java
中的线程状态被明确地定义在Thread.State
中:
public enum State {
/**
* 新建
*/
NEW,
/**
* 可运行
*/
RUNNABLE,
/**
* 阻塞
*/
BLOCKED,
/**
* 等待
*/
WAITING,
/**
* 超时等待
*/
TIMED_WAITING,
/**
* 终止
*/
TERMINATED;
}
下面是各状态的说明:
线程状态 | 说明 |
---|---|
NEW | 一个线程被创建出来,但是还没有启动(调用Thread.start() 方法)的时候。 |
RUNNABLE | 一个正在 Java 虚拟机中执行的线程处于这一状态。 |
BLOCKED | 一个正在阻塞等待一个监视器锁的线程处于这一状态。 |
WAITING | 一个正在无限期等待另一个线程执行一个特定的动作(通知或中断)的线程处于这一状态。 |
TIMED_WAITING | 一个正在有限的时间内等待另一个线程执行一个特定的动作(通知或中断)的线程处于这一状态。 |
TERMINATED | 一个已经退出的线程处于这一状态。 |
1.2 线程状态转换图
2 线程状态详解
2.1 NEW
(新建状态)
- 线程被
new
创建出来后,但是还没有执行线程的start()
方法,这时候线程是没有启动的,此状态就是NEW
状态。 - 想要启动一个线程,必须执行
start()
方法。如果执行run()
方法,只会在调用方所在的线程中执行,并没有启动一个新的线程。
2.2 RUNNABLE
(可运行状态)
RUNNABLE
状态是JVM
虚拟机对线程状态的一种描述,不是操作系统对线程状态的描述。JVM
虚拟机中的线程状态与操作系统中的线程状态不是一回事。RUNNABLE
状态实际上对应了操作系统中的READY
(就绪)状态、RUNNING
(运行)状态、部分WAITING
状态。- 处于
RUNNABLE
状态的线程表示正在Java
虚拟机中运行,但是它可能正在等待来自于操作系统的其它资源,比如处理器。
注意:进行阻塞式
I/O
操作时,Java
的线程状态还是RUNNABLE
,并不是BLOCKED
和WAITING
!!!
看下面的例子:
// 创建一个线程,等待I/O输入
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try (Scanner in = new Scanner(System.in);) {
String input = in.nextLine();
System.out.println(input);
} catch (Exception e) {
e.printStackTrace();
}
}
});
// 启动这个线程
thread.start();
// 确保子线程被启动
Thread.sleep(1000);
System.out.println(thread.getState()); // RUNNABLE
2.3 BLOCKED
(阻塞状态)
BLOCKED
状态不是通常意义上的 “ 阻塞 ”,线程的BLOCKED
状态是针对于synchronized
代码块或方法而言的。
线程在请求获取
monitor
锁时,如果这个锁已经被其他线程获取了,那么这个线程将要 “ 阻塞 ” 等待着获取这个monitor
锁,以便进入synchronized
代码块/方法。或者在这个线程已经进入了同步块/方法之后,然后调用了
Object.wait()
方法,这个线程将会释放该锁,并进入锁的等待队列(wait set
)中。之后被其他线程唤醒,这个时候这个锁可能已经被其他线程获取了,所以这个线程需要 “ 阻塞 ” 等待着重新获取monitor
锁,以便 再次 进入这个synchronized
代码块/方法,然后从上次wait()
的地方恢复执行。
- 线程等待着获取锁被阻塞在同步块之外的这个状态就是
BLOCKED
状态。
BLOCKED
状态可以视作是一种特殊的 WAITING
,特指等待 锁。
注意:这一状态的进入及解除都不受我们控制,当锁可用时,线程就会从阻塞状态中恢复。
2.4 WAITING
(等待状态)
一个线程正在无限期等待另一个线程执行一个特别的动作,这个状态就是
WAITING
。
一个线程进入WAITING
状态是因为调用了以下方法:
-
不带超时时间的
Object.wait()
方法 -
不带超时时间的
Thread.join()
方法 -
LockSupport.park()
。
其他线程执行的特别动作,可能是:
-
调用
Object.notify()
或者Object.notifyAll()
-
线程结束(针对的是调用了这个线程的
Thread.join()
方法)
与BLOCKED
不同在于,进入WAITING
状态的线程,会被放入wait set
中。这时,线程不再活动,不再参与调度,因此不会浪费CPU
资源,也不会竞争锁,直到另一个线程执行一个特别的动作,这个线程才会被唤醒。
处于WAITING
状态的线程被唤醒之后,如果能够获得锁,线程就会从WAITING
状态变成RUNNABLE
状态;否则,从wait set
出来,又进入entry set
,需要去竞争锁,线程就从WAITING
状态变成BLOCKED
状态。
2.5 TIMED_WAITING
(超时等待状态)
TIMED_WAITING
是带超时时间的WAITING
状态。
一个正在限时等待另一个线程执行一个动作的线程处于这一状态。
一个线程进入TIMED_WAITING
状态是因为调用以下方法:
- 带超时时间的
Thread.sleep
- 带超时时间的
Object.wait
- 带超时时间的
Thread.join
LockSupport.parkNanos
LockSupport.parkUntil
超时时间到,即使没有被唤醒,线程也会自己醒来。
2.6 TERMINATED
(终止状态)
一个已经退出的线程处于这一状态。