当前位置:首页 > 单片机 > 架构师社区
[导读]来自:冰河技术   写在前面 在【高并发专题】中的《高并发之——线程与多线程》一文中,我们简单介绍了线程的生命周期和线程的几个重要状态,并以代码的形式实现了线程是如何进入各个状态的。今天,我们就结合操作系统线程和编程语言线程再次深入探讨线程的生

线程的生命周期其实没有我们想象的那么简单!!

来自:冰河技术  

写在前面

在【高并发专题】中的《高并发之——线程与多线程》一文中,我们简单介绍了线程的生命周期和线程的几个重要状态,并以代码的形式实现了线程是如何进入各个状态的。今天,我们就结合操作系统线程和编程语言线程再次深入探讨线程的生命周期问题,线程的生命周期其实没有我们想象的那么简单!!

理解线程的生命周期本质上理解了生命周期中各个节点的状态转换机制就可以了。

接下来,我们分别就通用线程生命周期和Java语言的线程生命周期分别进行详细说明。

通用的线程生命周期

通用的线程生命周期总体上可以分为五个状态:初始状态、可运行状态、运行状态、休眠状态和终止状态。

我们可以简单的使用下图来表示这五种状态。

线程的生命周期其实没有我们想象的那么简单!!

初始状态

线程已经被创建,但是不允许分配CPU执行。需要注意的是:这个状态属于编程语言特有,这里指的线程已经被创建,仅仅指在编程语言中被创建,在操作系统中,并没有创建真正的线程。

可运行状态

线程可以分配CPU执行。此时,操作系统中的线程被成功创建,可以分配CPU执行。

运行状态

当操作系统中存在空闲的CPU,操作系统会将这个空闲的CPU分配给一个处于可运行状态的线程,被分配到CPU的线程的状态就转换成了运行状态

休眠状态

运行状态的线程调用一个阻塞的API(例如,以阻塞的方式读文件)或者等待某个事件(例如,等待某个条件变量等),线程的状态就会转换到休眠状态。此时线程会释放CPU资源,休眠状态的线程没有机会获得CPU的使用权。一旦等待的条件出现,线程就会从休眠状态转换到可运行状态。

终止状态

线程执行完毕或者出现异常就会进入终止状态,终止状态的线程不会切换到其他任何状态,这也意味着线程的生命周期结束了。

以上就是通用的线程生命周期,下面,我们再看对比看下Java语言中的线程生命周期。

Java中的线程生命周期

Java中的线程生命周期总共可以分为六种状态:初始化状态(NEW)、可运行/运行状态(RUNNABLE)、阻塞状态(BLOCKED)、无时限等待状态(WAITING)、有时限等待状态(TIMED_WAITING)、终止状态(TERMINATED)。

需要大家重点理解的是:虽然Java语言中线程的状态比较多,但是,其实在操作系统层面,Java线程中的阻塞状态(BLOCKED)、无时限等待状态(WAITING)、有时限等待状态(TIMED_WAITING)都是一种状态,即通用线程生命周期中的休眠状态。也就是说,只要Java中的线程处于这三种状态时,那么,这个线程就没有CPU的使用权。

理解了这些之后,我们就可以使用下面的图来简单的表示Java中线程的生命周期。

线程的生命周期其实没有我们想象的那么简单!!

我们也可以这样理解阻塞状态(BLOCKED)、无时限等待状态(WAITING)、有时限等待状态(TIMED_WAITING),它们是导致线程休眠的三种原因!

接下来,我们就看看Java线程中的状态是如何转化的。

RUNNABLE与BLOCKED的状态转换

只有一种场景会触发这种转换,就是线程等待synchronized隐式锁。synchronized修饰的方法、代码块同一时刻只允许一个线程执行,其他的线程则需要等待。此时,等待的线程就会从RUNNABLE状态转换到BLOCKED状态。当等待的线程获得synchronized隐式锁时,就又会从BLOCKED状态转换到RUNNABLE状态。

这里,需要大家注意:线程调用阻塞API时,在操作系统层面,线程会转换到休眠状态。但是在JVM中,Java线程的状态不会发生变化,也就是说,Java线程的状态仍然是RUNNABLE状态。JVM并不关心操作系统调度相关的状态,在JVM角度来看,等待CPU使用权(操作系统中的线程处于可执行状态)和等待IO操作(操作系统中的线程处于休眠状态)没有区别,都是在等待某个资源,所以,将其都归入了RUNNABLE状态。

我们平时所说的Java在调用阻塞API时,线程会阻塞,指的是操作系统线程的状态,并不是Java线程的状态。

RUNNABLE与WAITING状态转换

线程从RUNNABLE状态转换成WAITING状态总体上有三种场景。

场景一

获得synchronized隐式锁的线程,调用无参的Object.wait()方法。此时的线程会从RUNNABLE状态转换成WAITING状态。

场景二

调用无参数的Thread.join()方法。其中join()方法是一种线程的同步方法。例如,在threadA线程中调用threadB线程的join()方法,则threadA线程会等待threadB线程执行完。而threadA线程在等待threadB线程执行的过程中,其状态会从RUNNABLE转换到WAITING。当threadB执行完毕,threadA线程的状态则会从WAITING状态转换成RUNNABLE状态。

场景三

调用LockSupport.park()方法,当前线程会阻塞,线程的状态会从RUNNABLE转换成WAITING。调用LockSupport.unpark(Thread thread)可唤醒目标线程,目标线程的状态又会从WAITING状态转换到RUNNABLE。

RUNNABLE与TIMED_WAITING状态转换

总体上可以分为五种场景。

场景一

调用带超时参数的Thread.sleep(long millis)方法;

场景二

获得synchronized隐式锁的线程,调用带超时参数的Object.wait(long timeout)参数;

场景三

调用带超时参数的Thread.join(long millis)方法;

场景四

调用带超时参数的LockSupport.parkNanos(Object blocker, long deadline)方法;

场景五

调用带超时参数的LockSuppor.parkUntil(long deadline)方法。

从NEW到RUNNABLE状态

Java刚创建出来的Thread对象就是NEW状态,创建Thread对象主要有两种方法,一种是继承Thread对象,重写run()方法;另一种是实现Runnable接口,重写run()方法。

注意:这里说的是创建Thread对象的方法,而不是创建线程的方法,创建线程的方法包含创建Thread对象的方法。

继承Thread对象

public class ChildThread extends Thread{
    @Override
    public void run(){
        //线程中需要执行的逻辑
    }
}
//创建线程对象
ChildThread childThread = new ChildThread();

实现Runnable接口

public class ChildRunnable implements Runnable{
    @Override
    public void run(){
        //线程中需要执行的逻辑
    }
}
//创建线程对象
Thread childThread = new Thread(new ChildRunnable());

处于NEW状态的线程不会被操作系统调度,因此也就不会执行。Java中的线程要执行,就需要转换到RUNNABLE状态。从NEW状态转换到RUNNABLE状态,只需要调用线程对象的start()方法即可。

//创建线程对象
Thread childThread = new Thread(new ChildRunnable());
//调用start()方法使线程从NEW状态转换到RUNNABLE状态
childThread.start();

RUNNABLE到TERMINATED状态

线程执行完run()方法后,或者执行run()方法的时候抛出异常,都会终止,此时为TERMINATED状态。如果我们需要中断run()方法,可以调用interrupt()方法。

写在最后

最后,附上并发编程需要掌握的核心技能知识图,祝大家在学习并发编程时,少走弯路。

线程的生命周期其实没有我们想象的那么简单!!

特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:

线程的生命周期其实没有我们想象的那么简单!!

长按订阅更多精彩▼

线程的生命周期其实没有我们想象的那么简单!!

如有收获,点个在看,诚挚感谢

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭