java线程基础巩固---线程生命周期以及start方法源码剖析

时间:2022-10-10 09:38:20

上篇中介绍了如何启动一个线程,通过调用start()方法才能创建并使用新线程,并且这个start()是非阻塞的,调用之后立马就返回的,实际上它是线程生命周期环节中的一种,所以这里阐述一下线程的一个完整生命周期,里面涉及的一些状态目前还未学习到,没有关系,先有个全局观,之后都会涉及到滴。

线程的生命周期:

①、new状态:

当新建一个Thread对象时,此时的状态就是new状态:

java线程基础巩固---线程生命周期以及start方法源码剖析

注:这时线程还没有创建。

②、runnable状态:

当执行了Thread.start()方法之后,并不代表线程立即就能够执行,还得由CPU调度,所以此时是一个Runnable状态,也就是可以执行的状态。

java线程基础巩固---线程生命周期以及start方法源码剖析

③、running状态:

当CPU分配给了可运行的线程执行权时,这时线程就真正处理运行状态了:

java线程基础巩固---线程生命周期以及start方法源码剖析

④、blocked状态:

当运行的线程调用了wait、sleep、锁时,会从running状态变为blocked状态:

java线程基础巩固---线程生命周期以及start方法源码剖析

当blocked状态结束之后,比如sleep结束了,这时它不是直接就回到了running状态了,而是先回到runnable状态:

java线程基础巩固---线程生命周期以及start方法源码剖析

另外在running状态的线程可能被cpu把执行权切走了,也就是调度给其它线程了,这时running状态就会回到runnable状态了:

java线程基础巩固---线程生命周期以及start方法源码剖析

⑤、teminated状态:

最后就是线程结束状态,有几个状态都可能到线程结束状态:

  • running正在运行的线程正常执行完,也就到了结束状态了:
    java线程基础巩固---线程生命周期以及start方法源码剖析
  • 在blocked状态,比如wait状态被打断了,也有可能进入结束状态:
    java线程基础巩固---线程生命周期以及start方法源码剖析
  • 在runnable状态中,如果出现一些异外情况线程死了,也有可能进入结束状态:
    java线程基础巩固---线程生命周期以及start方法源码剖析

start()源码简单剖析:

先来看一下start()在JDK官方文档的说明:

java线程基础巩固---线程生命周期以及start方法源码剖析

如何理解,结合代码,这里还是用上篇中的代码为例:
java线程基础巩固---线程生命周期以及start方法源码剖析

java线程基础巩固---线程生命周期以及start方法源码剖析

所以这两个线程是:main启动线程、Read-Thread新建的线程。

接着再看文档描述:

java线程基础巩固---线程生命周期以及start方法源码剖析

那如果调用两次呢?

java线程基础巩固---线程生命周期以及start方法源码剖析

java线程基础巩固---线程生命周期以及start方法源码剖析

如文档描述所示,抛异常了。

那有个疑问:为啥不直接调run方法,而非得通过start()方法去启动呢?

下面试试直接调run方法:

java线程基础巩固---线程生命周期以及start方法源码剖析

java线程基础巩固---线程生命周期以及start方法源码剖析

下面来看看start()方法内部到底做了哪些事情呢?

java线程基础巩固---线程生命周期以及start方法源码剖析

java线程基础巩固---线程生命周期以及start方法源码剖析

其实这种设计技巧是一种模板方法,下面来编写一个模板方法来体会Thread的start()设计的思想:

涉及到的设计模式:

java线程基础巩固---线程生命周期以及start方法源码剖析

java线程基础巩固---线程生命周期以及start方法源码剖析

另外正常的模板方法是需要将定声明为final类型的:

java线程基础巩固---线程生命周期以及start方法源码剖析

当然Thread的start()方法木有将它声明为final类型:

java线程基础巩固---线程生命周期以及start方法源码剖析

这样子类就可以对它进行复写:

java线程基础巩固---线程生命周期以及start方法源码剖析

跟严格意义上的模板方法还是有些区别,不过可以思想是类似的。

线程概念总结:

这是第二篇对线程基础的巩固,涉及到了一些概念,好的学习方法是要善于总结的,所以这里对学的知识总结一下:

①、java应用程序的main函数是一个线程,是被JVM启动时调用的,线程的名字叫main。

②、实现一个线程,必须创建Thread实例,override run方法,并且调用start方法。

③、在JVM启动后,实际上有多个线程,但是至少有一个非守护进程。

④、当你调用一个线程start方法之后,此时至少有两个线程:一个是调用你的线程,另一个是执行run方法的线程【新创建的线程】。

⑤、线程的生命周期分为:new、runnable、running、blocked、teminated。