线程的生命周期分几个阶段

5个阶段:1、新建,是刚使用new方法,new出来的线程;2、就绪,是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段;3、运行,当就绪的线程被调度并获得CPU资源时,便进入运行状态;4、阻塞,在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态;5、销毁,线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁。

本教程操作环境:windows7系统、Dell G3电脑。

线程的生命周期包含5个阶段,包括:新建、就绪、运行、阻塞、销毁。完整的生命周期图如下:

0.webp

当线程进入运行状态后,一般的操作系统是采用抢占式的方式来让线程获得CPU。所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞、就绪之间切换。

1、新建(new)

新建:使用new方法,new出来线程,此时仅仅由JAVA虚拟机为其分配内存,并初始化成员变量的值。此时仅仅是个对象。

2、就绪(runnable)

就绪:就是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行;
该线程进入就绪状态,JAVA虚拟机会为其创建方法调用栈和程序计数器。线程的执行是由底层平台控制, 具有一定的随机性。

3、运行(running)

运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run方法定义了线程的操作和功能;(当处于就绪状态的线程获得CPU,它就会执行run()方法)
对于一个单核cpu(或者是一个内核)来说,只能同时执行一条指令,而JVM通过快速切换线程执行指令来达到多线程的,真正处理器就能同时处理一条指令,只是这种切换速度很快,我们根本不会感知到。为了线程切换后能恢复到正确的执行位置,每条线程都有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储。
当一个线程开始运行后,它不可能一直持有CPU(除非该线程执行体非常短,瞬间就执行结束了)。所以,线程在执行过程中需要被中断,目的是让其它线程获得执行的CPU的机会。线程的调度细节取决于底层平台所采用的策略。

4、阻塞(blocked)

阻塞:在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态。原因如下:

1.等待I/O流的输入输出
2.等待网络资源,即网速问题
3.调用sleep()方法,需要等sleep时间结束
4.调用wait()方法,需要调用notify()唤醒线程
5.其他线程执行join()方法,当前线程则会阻塞,需要等其他线程执行完。

状态切换图如下:

1.webp

5、销毁(terminated)

如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源。

1、run()/call()方法执行完成,线程正常结束;
2、线程抛出一个未捕获的Exception或Error;
3、直接调用线程的stop()方法结束该线程——该方法容易导致死锁,通常不建议使用。

扩展知识:CPU时间片

操作系统层面有个晶振,有点像和尚在不停的撞钟,每隔很短很短的一段时间撞一次,将CPU的时间拆成一个一个的时间片;各个线程其实是不停的去抢一个个的时间片;时间片到点后,还是要重新抢(保证所有的线程都有机会抢到CPU去执行自己的逻辑;公平性)

新建状态

我们来看下面一段代码:

Thread t1 = new Thread();

这里的创建,仅仅是在JAVA的这种编程语言层面被创建,而在操作系统层面,真正的线程还没有被创建。只有当我们调用了 start() 方法之后,该线程才会被创建出来,进入Runnable状态。只有当我们调用了 start() 方法之后,该线程才会被创建出来

更多相关知识,请访问常见问题栏目!

推荐阅读