面试官问:线程生命周期与状态转换是什么?一张图+员工一天比喻,彻底拿下这道必考题(附图解+比喻+避坑指南)

📅 2026/7/21 9:42:14
面试官问:线程生命周期与状态转换是什么?一张图+员工一天比喻,彻底拿下这道必考题(附图解+比喻+避坑指南)
面试官问线程生命周期与状态转换是什么一张图员工一天比喻彻底拿下这道必考题附图解比喻避坑指南预计阅读12分钟 你是不是也这样能说出“新建、运行、阻塞、死亡”几个词但面试官一追问“sleep和wait有什么区别”“BLOCKED和WAITING有什么不同”就答不上来了今天一张图 一个员工一天故事 状态转换详解 五道追问彻底拿下这道题。摘要Java线程的生命周期由Thread.State枚举定义共6种状态NEW新建、RUNNABLE可运行、BLOCKED阻塞、WAITING无限等待、TIMED_WAITING计时等待、TERMINATED终止。线程状态会因start()、wait()、notify()、sleep()、join()、锁竞争等操作而转换。本文用“办公室员工”比喻 六种状态详解 状态转换图 sleepvswait深度对比 5道面试官追问彻底讲透这道并发编程必考题。一句话线程的生命周期就是一场“上班”之旅——从入职到离职中间可能被叫去开会阻塞、等同事回复等待、倒计时休息计时等待。我是折哥《Java 85题图解版》系列连载中已更新34题建议收藏本系列。每周2-3篇85题通关路线一键追完。点击关注第一时间收到每篇新题推送。上一篇面试官问MyBatis面试专题含源码MP下一篇预告面试官问synchronized和ReentrantLock有什么区别全部85题点击查看总目录关注专栏追更不迷路一句话总结线程的生命周期就是一场“上班”之旅——从入职到离职中间可能被叫去开会阻塞、等同事回复等待、倒计时休息计时等待。NEW / RUNNABLE刚拿到OfferNEW→ 正式入职上班RUNNABLE有时在工作Running有时等任务Ready→ 像员工入职后正常上班。BLOCKED等会议室锁被占用→ 像员工想开会但会议室被占只能在门口排队等。WAITING / TIMED_WAITING等同事回复WAITING无限等待需别人叫醒倒计时休息TIMED_WAITING设闹钟超时自动醒 → 像员工发消息等回复无限等或趴桌睡10分钟计时等。背诵口诀New出来start跑锁竞争Blockedwait无期sleep计时run完终止。核心设计理念状态是线程在不同时间点的“快照”理解状态转换是编写正确并发程序的前提。 面试还原面试官Java线程有哪些状态能介绍一下线程的完整生命周期吗这是Java并发编程中最基础但也最核心的面试题直接进入正题。 一图看懂线程6种状态与转换全貌 生活比喻办公室员工的一天场景设定你是一家公司的员工线程你的工作状态就是线程的生命周期状态。NEW新建 刚拿到Offer你通过了面试拿到了Offernew Thread()但还没去公司报到还没调用start()。公司系统里有你的档案但你还没开始工作。RUNNABLE可运行 正常上班你正式入职开始工作start()。你有时候在工作Running——正在CPU上执行有时候在等领导分配任务Ready——等待CPU调度。这两种状态在Java层面统称为RUNNABLE。BLOCKED阻塞 等会议室你想开会但会议室对象锁被其他同事占用了。你只能站在会议室门口等synchronized等待锁等同事开完会出来你才能进去。WAITING无限等待 等同事回复你给同事发了一条消息问问题然后一直等着wait()/join()直到同事回复你notify()/notifyAll()你才能继续工作。你不知道要等多久可能是1分钟也可能是1小时。TIMED_WAITING计时等待 倒计时休息你设置了一个闹钟休息10分钟sleep(10000)/wait(10000)闹钟响了你自动醒来继续工作。或者你在等一个任务但只愿意等30秒超时就放弃。TERMINATED终止 离职你完成了所有工作run()执行完毕或者出了严重问题被开除未捕获异常正式离开公司。离职后不能再回来上班。 六种状态详解面试速查版状态总览状态枚举值进入条件退出条件NEWThread.State.NEWnew Thread()调用start()RUNNABLEThread.State.RUNNABLEstart()等待锁→BLOCKED等待唤醒→WAITING/TIMED_WAITINGBLOCKEDThread.State.BLOCKED等待synchronized锁获得锁WAITINGThread.State.WAITINGwait()/join()/park()notify()/notifyAll()/unpark()TIMED_WAITINGThread.State.TIMED_WAITINGsleep()/wait(timeout)等超时或被动唤醒TERMINATEDThread.State.TERMINATEDrun()结束或异常无终态BLOCKED vs WAITING vs TIMED_WAITING高频区分点维度BLOCKEDWAITINGTIMED_WAITING原因等待获取锁等待被显式唤醒等待超时或唤醒典型APIsynchronizedwait()、join()、park()sleep()、wait(timeout)、join(timeout)如何退出锁被释放被notify()/unpark()超时或被唤醒是否释放锁不释放等待锁释放锁释放锁wait时记忆口诀BLOCKED等锁WAITING等人叫TIMED_WAITING等闹钟响。 关键API与状态转换详解1.sleep()—— RUNNABLE → TIMED_WAITING → RUNNABLE// 当前线程暂停执行指定的毫秒数不释放任何锁Thread.sleep(1000);状态转换RUNNABLE → TIMED_WAITING → RUNNABLE是否释放锁❌不释放仅释放CPU唤醒方式超时自动唤醒使用位置任何地方都可以调用2.wait()—— RUNNABLE → WAITING/TIMED_WAITING → BLOCKED → RUNNABLEsynchronized(lock){lock.wait();// 无限等待 → WAITINGlock.wait(1000);// 计时等待 → TIMED_WAITING}状态转换RUNNABLE → WAITING/TIMED_WAITING → BLOCKED → RUNNABLE是否释放锁✅释放锁唤醒方式notify()/notifyAll()或超时⚠️ 前提条件必须在synchronized块中调用否则抛出IllegalMonitorStateException归属Object类的方法3.join()—— RUNNABLE → WAITING/TIMED_WAITING → RUNNABLEthread.join();// 等待thread执行完毕 → WAITINGthread.join(1000);// 最多等待1秒 → TIMED_WAITING状态转换当前线程进入WAITING/TIMED_WAITING等待目标线程终止本质内部调用wait()实现4.yield()—— RUNNABLERunning → ReadyThread.yield();// 让出CPU时间片状态转换RUNNABLE内部从Running→Ready状态枚举不变效果提示调度器当前线程愿意让出CPU但不保证5.synchronized—— RUNNABLE → BLOCKED → RUNNABLEsynchronized(lock){// 如果lock被其他线程持有当前线程进入BLOCKED}状态转换RUNNABLE → BLOCKED → RUNNABLE获得锁后从BLOCKED回到RUNNABLE 高频面试追问5道大厂真题追问1sleep()和wait()有什么区别⭐ 最高频回答要点释放锁、所属类、唤醒方式、使用前提。详细回答维度Thread.sleep()Object.wait()释放锁❌不释放对象锁✅释放对象锁所属类Thread类的静态方法Object类的实例方法唤醒方式超时自动唤醒需要notify()/notifyAll()唤醒使用前提任何地方都可调用必须在synchronized块中调用用途线程暂停执行线程间通信/协调总结sleep是让线程“歇一会儿”不放手里的资源wait是让线程“先别干了把资源让出来”等别人通知再继续。追问2BLOCKED和WAITING有什么区别回答要点BLOCKED被动等待锁释放WAITING主动等待被唤醒。详细回答BLOCKED线程被动等待获取synchronized对象锁。锁被其他线程持有JVM将线程放入锁的等待队列。WAITING线程主动调用了wait()/join()/park()等待另一个线程执行特定操作来唤醒它。关键区别BLOCKED是“别人不放手我进不去”WAITING是“我主动停下来等别人叫我”。追问3线程从RUNNABLE直接到TERMINATED可能吗回答要点可能。run()执行完毕或异常退出时发生。详细回答可以。线程的run()方法正常执行完毕后直接从RUNNABLE转到TERMINATED。或者run()中抛出未捕获异常也会直接结束进入TERMINATED。这是线程生命周期最常见的结束路径。追问4Thread.interrupt()对线程状态有什么影响回答要点设置中断标志影响WAITING/TIMED_WAITING状态。详细回答interrupt()不会直接改变线程状态但会设置线程的中断标志位。如果线程在WAITING或TIMED_WAITING状态如sleep()、wait()、join()中interrupt()会抛出InterruptedException线程从等待状态被唤醒转为RUNNABLE如果线程在RUNNABLE状态interrupt()只设置中断标志线程继续运行可以通过Thread.interrupted()检查追问5线程终止后还能再调用start()吗回答要点不能。会抛出IllegalThreadStateException。详细回答不能。一个线程的start()方法只能调用一次。线程进入TERMINATED状态后生命周期已经结束不能再重新启动。如果再次调用start()会抛出IllegalThreadStateException。 避坑指南序号错误做法正确做法后果1在非synchronized块中调用wait()先获取对象锁再调用IllegalMonitorStateException2认为sleep()会释放锁明确sleep()只释放CPU死锁或性能问题3认为wait()后线程直接RUNNABLEwait()后先进入BLOCKED竞争锁误以为唤醒后立即执行4重复启动一个已终止的线程检查线程状态后再start()IllegalThreadStateException5混淆BLOCKED和WAITING区分锁等待和主动等待错误定位问题根源 可运行验证代码publicclassThreadStateDemo{privatestaticfinalObjectlocknewObject();publicstaticvoidmain(String[]args)throwsInterruptedException{// 1. NEW状态ThreadthreadnewThread(()-{// 线程执行体});System.out.println(1. 刚创建: thread.getState());// NEW// 2. RUNNABLE状态thread.start();System.out.println(2. 启动后: thread.getState());// RUNNABLE// 3. BLOCKED状态演示ThreadblockedThreadnewThread(()-{synchronized(lock){System.out.println(获得锁);}});// 主线程先持有锁synchronized(lock){blockedThread.start();Thread.sleep(100);System.out.println(3. 等待锁: blockedThread.getState());// BLOCKED}// 4. WAITING状态演示ThreadwaitingThreadnewThread(()-{synchronized(lock){try{lock.wait();}catch(InterruptedExceptione){Thread.currentThread().interrupt();}}});synchronized(lock){waitingThread.start();Thread.sleep(100);System.out.println(4. 无限等待: waitingThread.getState());// WAITINGlock.notify();}// 5. TIMED_WAITING状态演示ThreadtimedThreadnewThread(()-{try{Thread.sleep(5000);}catch(InterruptedExceptione){Thread.currentThread().interrupt();}});timedThread.start();Thread.sleep(100);System.out.println(5. 计时等待: timedThread.getState());// TIMED_WAITING// 6. TERMINATED状态演示ThreadterminatedThreadnewThread(()-{});terminatedThread.start();terminatedThread.join();System.out.println(6. 终止: terminatedThread.getState());// TERMINATED}}❓ 评论区挑战问题下面代码中线程t处于什么状态ThreadtnewThread(()-{synchronized(lock){try{lock.wait();}catch(InterruptedExceptione){e.printStackTrace();}}});t.start();// 假设此时lock已被其他线程持有且其他线程没有调用notify()A. NEWB. RUNNABLEC. BLOCKEDD. WAITING 欢迎在评论区写出你的答案和理由我会在下一篇文章发布后更新本文公布答案及错误选项逐项解析。✅ 答案公布正确答案D. WAITING解析线程t持有lock对象锁后调用了lock.wait()进入WAITING状态wait()会让当前线程释放锁并进入等待队列直到被notify()唤醒注意这里不是BLOCKED——BLOCKED是“等锁”WAITING是“等唤醒”即使lock被其他线程持有也是当前线程先获得锁再wait释放所以状态是WAITING而非BLOCKED 总结状态一句话概括典型API能否直接进入NEW刚创建未启动new Thread()—RUNNABLE可运行/正在运行start()✅BLOCKED等待锁synchronized❌被动WAITING无限等待唤醒wait()/join()/park()✅主动TIMED_WAITING计时等待sleep()/wait(timeout)✅主动TERMINATED生命周期结束run()结束❌终态面试官最看重的三个点6种状态完整列表能准确说出NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATEDBLOCKED vs WAITING vs TIMED_WAITING能区分三种“非运行”状态的根本原因sleep vs wait能说清释放锁、所属类、唤醒方式的差异 系列导航上一篇面试官问MyBatis面试专题含源码MP下一篇预告面试官问synchronized和ReentrantLock有什么区别全部85题目录点击查看关注专栏每周2-3篇一键追更搭配学习效果更佳本篇图解帮你快速建立知识画面记忆如果想深入理解源码实现和实战避坑细节可以配合姊妹系列《Java 100天进阶之路》对应章节一起学从零基础到上岗就业108篇完整学习地图每篇标配生活类比 可运行代码 避坑表 面试高频题 练习题不背八股文真正讲透“为什么”。 《Java 100天进阶之路》完整目录导航学习建议图解系列负责“快速建立知识图谱”进阶系列负责“深入理解原理”两个系列搭配使用面试备考效率翻倍。你在实际开发中遇到过因为线程状态理解不到位导致的Bug吗比如wait()忘记在synchronized块中调用欢迎评论区分享你的故事