Java 并发编程实战
王宝令
资深架构师
72485 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 51 讲
学习攻略 (1讲)
Java 并发编程实战
15
15
1.0x
00:00/00:00
登录|注册

09 | Java线程(上):Java线程的生命周期

从RUNNABLE到TERMINATED状态
从NEW到RUNNABLE状态
RUNNABLE与TIMED_WAITING的状态转换
RUNNABLE与WAITING的状态转换
RUNNABLE与BLOCKED的状态转换
TERMINATED(终止状态)
TIMED_WAITING(有时限等待)
WAITING(无时限等待)
BLOCKED(阻塞状态)
RUNNABLE(可运行/运行状态)
NEW(初始化状态)
终止状态
休眠状态
运行状态
可运行状态
初始状态
代码分析
jstack命令和Java VisualVM工具
线程生命周期具备通用性
理解Java线程的各种状态对于诊断多线程Bug有帮助
interrupt()方法
状态转换
Java中线程的生命周期
通用的线程生命周期
课后思考
总结
Java线程的生命周期

该思维导图由 AI 生成,仅供参考

在 Java 领域,实现并发程序的主要手段就是多线程。线程是操作系统里的一个概念,虽然各种不同的开发语言如 Java、C# 等都对其进行了封装,但是万变不离操作系统。Java 语言里的线程本质上就是操作系统的线程,它们是一一对应的。
在操作系统层面,线程也有“生老病死”,专业的说法叫有生命周期。对于有生命周期的事物,要学好它,思路非常简单,只要能搞懂生命周期中各个节点的状态转换机制就可以了。
虽然不同的开发语言对于操作系统线程进行了不同的封装,但是对于线程的生命周期这部分,基本上是雷同的。所以,我们可以先来了解一下通用的线程生命周期模型,这部分内容也适用于很多其他编程语言;然后再详细有针对性地学习一下 Java 中线程的生命周期。

通用的线程生命周期

通用的线程生命周期基本上可以用下图这个“五态模型”来描述。这五态分别是:初始状态、可运行状态、运行状态、休眠状态终止状态
通用线程状态转换图——五态模型
这“五态模型”的详细情况如下所示。
初始状态指的是线程已经被创建,但是还不允许分配 CPU 执行。这个状态属于编程语言特有的,不过这里所谓的被创建,仅仅是在编程语言层面被创建,而在操作系统层面,真正的线程还没有创建。
可运行状态,指的是线程可以分配 CPU 执行。在这种状态下,真正的操作系统线程已经被成功创建了,所以可以分配 CPU 执行。
当有空闲的 CPU 时,操作系统会将其分配给一个处于可运行状态的线程,被分配到 CPU 的线程的状态就转换成了运行状态
运行状态的线程如果调用一个阻塞的 API(例如以阻塞方式读文件)或者等待某个事件(例如条件变量),那么线程的状态就会转换到休眠状态,同时释放 CPU 使用权,休眠状态的线程永远没有机会获得 CPU 使用权。当等待的事件出现了,线程就会从休眠状态转换到可运行状态。
线程执行完或者出现异常就会进入终止状态,终止状态的线程不会切换到其他任何状态,进入终止状态也就意味着线程的生命周期结束了。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Java线程的生命周期是多线程编程中的重要概念。本文详细介绍了Java线程的生命周期模型,包括各种状态之间的转换条件和示例,以及Java中线程状态与操作系统线程状态的区别。文章还解释了stop()和interrupt()方法的区别,以及被interrupt的线程如何收到通知。此外,文章强调了理解Java线程生命周期对于诊断多线程Bug的重要性,以及通过jstack命令或Java VisualVM工具导出线程栈信息进行并发问题诊断的重要性。总之,本文对于快速了解Java线程的生命周期及其状态转换机制提供了重要参考,对于学习其他语言的多线程编程也有很大的帮助。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 并发编程实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(122)

  • 最新
  • 精选
  • 姜戈
    可能出现无限循环,线程在sleep期间被打断了,抛出一个InterruptedException异常,try catch捕捉此异常,应该重置一下中断标示,因为抛出异常后,中断标示会自动清除掉! Thread th = Thread.currentThread(); while(true) { if(th.isInterrupted()) { break; } // 省略业务代码无数 try { Thread.sleep(100); }catch (InterruptedException e){ Thread.currentThread().interrupt(); e.printStackTrace(); } }

    作者回复: 👍👍👍

    2019-03-19
    12
    397
  • 虎虎❤️
    我的一位长辈曾告诉我,没有真正学不会的知识或者技术,只是缺乏好的老师。 有的人可以把复杂的知识讲明白,但是讲解的过程却也是晦涩难懂,不免落了下成。 而学习王老师的课,我一直都觉得很轻松。云淡风轻地就把并发知识抽丝剥茧,确是更显功力。另一方面,我觉得人的大脑更喜欢接受这些平易近人的文字。看似浅近的文字,却更能带领我深入的思考,留下更深刻的印象。反观一些看起来高端大气上档次的论述,让人觉得云山雾罩,好不容易看懂了,但看过后却什么也想不起来了。大概是读文章的时候脑细胞都用来和晦涩的文字做斗争了,已经没有空间去思考和记忆了。 再次感谢王老师给大家带来优秀的课程。

    作者回复: 看来我没必要写的很装了😂

    2019-03-19
    6
    122
  • Tristan
    为什么实战高并发程序设计医术中写道“Tread.stop()方法在结束线程时,会直接终止线程,并且会释放这个线程所持有的锁”,而您文中所写的“果线程持有 synchronized 隐式锁,也不会释放”??

    作者回复: 是我的错,我确认了一下,隐式锁可以释放。多谢多谢!!!

    2019-04-14
    16
    95
  • thas
    interrupt是中断的意思,在单片机开发领域,用于接收特定的事件,从而执行后续的操作。Java线程中,(通常)使用interrupt作为线程退出的通知事件,告知线程可以结束了。 interrupt不会结束线程的运行,在抛出InterruptedException后会清除中断标志(代表可以接收下一个中断信号了),所以我想,interrupt应该也是可以类似单片机一样作为一种通知信号的,只是实现通知的话,Java有其他更好的选择。 因InterruptedException退出同步代码块会释放当前线程持有的锁,所以相比外部强制stop是安全的(已手动测试)。sleep、join等会抛出InterruptedException的操作会立即抛出异常,wait在被唤醒之后才会抛出异常(就像阻塞一样,不被打扰)。 另外,感谢老师提醒,I/O阻塞在Java中是可运行状态,并发包中的lock是等待状态。

    作者回复: 能和硬件中断联系起来👍👍👍

    2019-03-19
    3
    48
  • Junzi
    当发起中断之后,Thread.sleep(100);会抛出InterruptedException异常,而这个抛出这个异常会清除当前线程的中断标识,导致th.isInterrupted()一直都是返回false的。 InterruptedException - if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.

    作者回复: 👍

    2019-03-26
    2
    38
  • 海鸿
    如果线程处于阻塞状态(BLOCKED),此时调用线程的中断方法,线程会又如何反应? 是否会像等待状态一样抛异常? 还是会像运行状态一样被标记为已中断状态? 还是不受到任何影响? 麻烦老师解答一下😁

    作者回复: 阻塞态的线程不响应中断,并发包里的锁有方法能够响应中断

    2019-03-19
    5
    20
  • WhoAmI
    老师,Java调用阻塞API时,Java层面是runnable,那仍然占用CPU吗,此时此线程在操作系统中是什么状态呢?这个问题好几个人都在问,能详细解释下吗?

    作者回复: 不占cpu,操作系统里是阻塞状态。

    2019-03-24
    17
  • cky.宇
    根据接口文档描述,stop()虽然也会中止线程并释放锁,但是没有提供一种补偿的机会,可能某个线程对共享对象进行了不完整的修改,此时如果stop后,该共享对象会继续被其他线程使用,造成线程安全问题。interrupt()则是提供给使用者一种被中断后补偿的机会,例如回滚之前的修改。个人理解是这样的,请老师指点一下。

    作者回复: 完全同意!

    2019-11-04
    2
    15
  • alias cd=rm -rf
    思考题,不能中断循环,异常捕获要放在while循环外面

    作者回复: 你这也是个办法

    2019-03-19
    5
    13
  • J.M.Liu
    感谢老师提醒,原来jvm层面的线程状态和os层面上的线程状态是不一样的,i/o挂起在jvm也是runable状态。另外并发包的lock其实是处于waitting状态。 但是有个疑问,jvm中blocked状态的线程和waitting状态的线程,除了处在不同的队列之外,还有没有什么区别呀?我这里问的区别包括jvm和os两个层面,谢谢老师

    作者回复: block不能响应中断,os里应该都是休眠状态,因为都不能获得cpu使用权

    2019-03-19
    2
    10
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部