在多线程操作系统中,通常是在一个进程中包括多个线程,每个线程都是作为利用CPU的基本单位,是花费最小开销的实体。
线程是有状态的,线程的状态被定义在Thread.State枚举中,在Java Doc中也有明确的解释:
![6332a6352b2c33098bdfbc68bf9a1614.jpeg](https://i-blog.csdnimg.cn/blog_migrate/8162f48f09868df60d509f6683404d3e.jpeg)
通过查看源码以及阅读Java Doc,我们可以知道,线程主要有以下6种状态:
NEW
当一个线程被创建出来的,但是还没调用start()方法的时候,他处于NEW状态。
RUNNABLE
在Java虚拟机中执行的线程处于这种状态
BLOCKED
正在等待锁的阻塞线程处于这种状态。
WAITING
不确定地等待另一个线程执行某个特定操作的线程就是处于这种状态,进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
TIMED_WAITING
在指定的等待时间内等待另一个线程执行某个操作的线程处于这种状态。该状态不同于WAITING,它可以在指定的时间后自行返回。
TERMINATED
已经退出的线程处于这种状态。
在指定的时间点,线程只能处于一种状态。但是需要注意的是这些状态表示的是虚拟机中线程的状态,而不是任何操作系统线程状态。
线程之间的状态是可以互相转换的,如下图:
![8ddaf8812bfa2e6c49cd4b8536566520.jpeg](https://i-blog.csdnimg.cn/blog_migrate/c16645ec18bb6f0e5be8fce816aaf2d2.jpeg)
上图,就是线程的6种状态的转换图,当遇到不同的操作或者事件的时候,线程的状态就可能发生变化。
Java Doc中说在Java虚拟机中正在执行的线程处于RUNNABLE状态,但是,在操作系统层面,一个线程要想被执行,是需要获得CPU的使用权的。
我们其实还可以把RUNNABLE状态进一步细化一下,根据线程是否获得了CPU的使用权分成两种:
就绪(READY):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中并分配cpu使用权 。
运行中(RUNNING):就绪(READY)的线程获得了cpu 时间片,开始执行程序代码。
![54550dbde6ba3ee0d558a125946158f7.jpeg](https://i-blog.csdnimg.cn/blog_migrate/9ced98fb36c8fa5c73fd36ad6939d3f3.jpeg)
也就是说,当一个线程被创建出来之后,执行了start方法之后,在没有获得cpu的使用权的时候,他就是就绪状态(READY),在获得了CPU的使用权,开始执行的时候,就是运行状态(RUNNING)了。
对于现在的分时操作系统来说,在单CPU情况下,所有的线程其实都是串行执行的。但是为了让我们看起来像是在并发执行,人们把CPU的执行分成很多个小的时间片。
哪个进程得到时间片,那个线程就执行,时间片到了之后,就要释放出CPU,再重新进行争抢时间片。
只要把时间片划分的足够细,那么多个程序虽然在不断的串行执行,但是看起来也像是在同时执行一样。
![1ac37f1271dd2dd667578f61a7568427.jpeg](https://i-blog.csdnimg.cn/blog_migrate/6ea423523d505fd338c7b19b0aa3b0c9.jpeg)
那么,CPU的时间片其实是很短的,一般也就是10-20毫秒左右。
那么,也就是说,在一秒钟之内,同一个线程可能一部分时间处于READY状态、一部分时间处于RUNNING状态。
那么如果,明确的给线程定义出RUNNING状态的话,有一个很大的问题,就是这个状态其实是不准的。
因为当我们看到线程是RUNNING状态的时候,很有可能他已经丢失了CPU时间片了。
对于线程的状态,我们只需要知道,他当前有没有在"正在参与执行"就行了,何为"参与执行"?
就是他的状态是可执行的,只要获得时间片,就能立即执行。
那这不就是RUNNABLE吗?
所以,Java就没有给线程定义RUNNING状态,而是定义了一个RUNNABLE状态。