线程到底有哪些状态?
线程的状态要分来看,一种是操作系统线程,一种是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从内核切出,将新线程的切入,带来上下文切换。除此之外,还需要切换寄存器、程序计数器、线程栈(包括操作栈、数据栈)等。
