线程到底有哪些状态?
线程的状态要分来看,一种是操作系统线程,一种是jvm线程(本质上是对操作系统线程的封装)。
操作系统线程状态:
jvm线程状态:
我们来看看jdk中Thread类下的状态枚举:
这里可能会觉得少了running状态,确实对于java线程来讲,runnable包括了就绪和运行。目前cpu进行抢占式执行,对时间片分配的单元一般在20ms左右,对如此短暂的时间进行状态切换没有必要。见【_ These states are virtual machine states which do not reflect 】
/**
* 线程的状态枚举,jvm线程一定会会处于一下状态之一
* NEW - 线程没有开始(new Thread())
* RUNNABLE - 线程在jvm中执行
* BLOCKED - 线程等待监视器锁
* WAITING - 线程无限等待另外一个线程的特定动作(wait -> notfiy, park -> unpark)
* TIMED_WAITING - 线程等待另外一个线程的特定动作直到超时
* TERMINATED - 线程终止
* 这里的线程状态是指jvm线程,并不映射操作系统线程状态。
*/
public enum Thread.State {
/**
* 线程没有开始
*/
NEW,
/**
* 线程正在jvm中执行,但也可能在等待cpu资源,或者IO资源
*/
RUNNABLE,
/**
* 线程在等待监视器锁,以便进入synchronized代码块
* 或者是调用Object.wait方法后重新进入待synchronized代码块
*/
BLOCKED,
/**
* 线程调用以下方法后处于等待状态:
* Object.wait
* Thread.join
* LockSupport.park
* 处于等待状态的线程需要另外一个线程的相关动作来触发,相应动作及状态变化如下:
* Object.wait -> Object.notify(notifyAll)(WAITING -> BLOCKED)
* Thread.join -> 目标线程终止(WAITING -> RUNNABLE)
* LockSupport.park -> LockSupport.unpark(WAITING -> RUNNABLE)
*/
WAITING,
/**
* 线程调用以下方法后处于有限时长的等待状态
* 要么和WAITING一样被触发唤醒,要么超时时间达到唤醒(注意多了一个sleep)
* Thread.sleep(long time)
* Object.wait(long time)
* Thread.join(long time)
* LockSupport.parkNanos/parkUntil
*/
TIMED_WAITING,
/**
* 线程退出
*/
TERMINATED;
}
操作系统线程和jvm线程的状态是怎么对应的?
操作系统线程 | jvm线程 |
---|---|
NEW | NEW |
RUNNABLE | RUNNABLE |
RUNNING | |
WAITING | BLOCKED |
WAITING | |
TIMED_WAITING | |
TERMINATED | TERMINATED |
类型 | 操作 | 操作系统线程 | jvm线程 | 备注 |
---|---|---|---|---|
操作系统 | read、write | RUNNING -> WAITING | RUNNABLE不变 | 由于操作系统线程让出cpu,所以对于jvm线程来说,处于却不会执行的RUNNABLE状态。 |
jvm | yield | RUNNING -> RUNNABLE | RUNNABLE不变 | |
sleep | RUNNING -> WAITING | RUNNING -> TIMED_WAITING | ||
wait | RUNNING -> WAITING | RUNNING -> WAITING | ||
synchronied | RUNNING -> WAITING | RUNNING -> BLOCKED |
什么情况下线程会发生切换?
- 线程阻塞
- 时间片轮转
- 主动放弃时间
线程切换的开销在哪里?
线程切换时,必然需要将旧线程的task_struct从内核切出,将新线程的切入,带来上下文切换。除此之外,还需要切换寄存器、程序计数器、线程栈(包括操作栈、数据栈)等。