线程的状态

你好,我是吴计可师,一个工作十多年的后端开发,曾就职京东、阿里等多家互联网头部企业。

点击下方👇关注公众号,带你一起复习后端技术,看看面试考点,补充积累技术知识,每天都为面试准备积累

文章可能会比较长,主要解析的非常详解,或涉及一些底层知识,供面试高阶难度用。可以根据自己实际理解情况合理取舍阅读


Java 中的线程有 7 种状态,这些状态在 Thread 类中通过 Thread.State 枚举定义。这些状态描述了线程的生命周期中的不同阶段。下面详细介绍这些线程状态:

01
New(新建状态)


线程被创建出来,但尚未开始执行。此时线程处于新建状态。

当线程对象被创建时,但 start() 方法还没有被调用

0

2
Runnable(可运行状态)


线程已经启动,正在等待 CPU 的时间片来执行。线程处于 可运行状态,但并不意味着线程正在执行,它可能正在等待 CPU 的调度。

何时进入此状态:当调用 start() 方法后,线程从 新建状态 进入 可运行状态。在操作系统中,线程已经准备好可以执行,调度器会决定什么时候实际执行它。

注意:在 Java 中,线程一旦进入了 可运行状态,并不意味着它会马上开始执行。它可能会等待 CPU 时间片,直到调度器给它分配 CPU 时间。


03
Blocked(阻塞状态)


线程因为等待获取锁(如同步锁)而进入 阻塞状态。当一个线程试图进入同步代码块时,如果该代码块的锁已经被其他线程占用,线程会进入 阻塞状态,直到它能够获得该锁。

何时进入此状态:当线程调用 synchronized 关键字修饰的方法或块,并且该线程无法获取锁时,它会进入 阻塞状态。


04
Waiting(等待状态)


线程进入 等待状态,意味着它在等待其他线程的通知来继续执行。常见的场景包括线程调用了 Object.wait()、Thread.join() 或 Lock.await() 等方法,导致线程进入此状态。

何时进入此状态:

  • 调用 Object.wait() 方法时。

  • 调用 Thread.join() 方法时(等待其他线程完成)。

  • 调用 Lock.await() 方法时(例如,使用 ReentrantLock)。

何时退出此状态:当其他线程调用了相应的通知方法(如 notify()、notifyAll())或超时到达时,线程才会从 等待状态 退出。


05
Timed Waiting(限时等待状态)


线程处于 限时等待状态,即它在等待一段指定时间后自动恢复运行,或者等待某个条件完成后继续执行。常见的场景包括调用 Thread.sleep()、Object.wait(long millis)、Thread.join(long millis) 或 Lock.lock(long millis) 等方法。

何时进入此状态:当调用下面的方法时,线程会进入 限时等待状态:

  • Thread.sleep(milliseconds)

  • Object.wait(milliseconds)

  • Thread.join(milliseconds)

  • Lock.lock(long timeout, TimeUnit unit)

何时退出此状态:当超时或其他条件触发时,线程会从 限时等待状态 退出。


06
Terminated(终止状态)


线程已经完成其任务,或由于异常、错误等原因被终止。此时,线程的生命周期结束,线程处于 终止状态。

何时进入此状态:线程在完成 run() 方法的执行或者因未捕获异常而停止时会进入 终止状态。


07
Interrupted(中断状态)


线程被中断时,它会进入 中断状态。中断是线程管理中的一种机制,线程可以被请求中断。调用 Thread.interrupt() 可以中断一个线程,线程会根据中断的方式进行相应的处理。并不是所有线程都会立即停止,线程需要在适当的位置检查中断标志并处理它。

  • 如果线程正在执行可中断的操作(如 sleep()、wait() 等),中断会导致这些方法抛出 InterruptedException,线程进入 中断状态,并且可以通过 Thread.interrupted() 来检查是否有中断请求。

注意:中断线程并不会立刻停止它,线程仍然需要检查中断标志并决定如何处理。


整体状态图示


08
直击面试


8.1 Thread.sleep() 和 Object.wait() 会导致线程进入哪种状态?

Thread.sleep(long millis):让线程进入 Timed Waiting(限时等待状态),等待指定的时间后,线程会恢复运行。Object.wait():让线程进入 Waiting(等待状态),直到被其他线程调用 notify() 或 notifyAll() 方法唤醒。

8.2 线程的 join() 方法会使线程进入哪个状态?

当一个线程调用 join() 方法时,它会使当前线程等待,直到被调用的线程执行完毕。因此,当前线程会进入 Waiting(等待状态),直到目标线程完成。


8.3 如果一个线程调用 notify() 或 notifyAll(),被唤醒的线程会进入什么状态?

当一个线程调用 notify() 或 notifyAll() 方法时,它会唤醒一个或多个处于 Waiting(等待状态) 的线程。被唤醒的线程将会重新进入 Runnable(可运行状态),等待操作系统的线程调度器分配 CPU 时间片执行。


8.4 一个线程进入 Waiting 状态后,如何退出该状态?

线程进入 Waiting(等待状态) 后,只有在以下几种情况时才会退出该状态:

  • 被其他线程调用 notify() 或 notifyAll() 唤醒,恢复为 Runnable(可运行状态)。

  • 被中断(即调用 interrupt()),如果线程在等待时被中断,通常会抛出 InterruptedException 异常,并进入中断状态。

8.5 Thread.sleep() 和 Object.wait() 有什么区别?

Thread.sleep():使当前线程进入 Timed Waiting(限时等待状态),在指定时间后恢复执行,不会释放锁。

Object.wait():使当前线程进入 Waiting(等待状态),直到被其他线程调用 notify() 或 notifyAll() 唤醒。调用 wait() 时,会释放持有的锁。


8.6 如何使一个线程在等待另一个线程执行完成后再执行?

可以通过调用另一个线程的 join() 方法来实现线程同步。调用 join() 的线程会进入 Waiting(等待状态),直到被调用的线程执行完毕。

Thread t1 = new Thread(() -> {     System.out.println("Thread 1");});Thread t2 = new Thread(() -> {     try {        t1.join();  // 等待 t1 执行完毕    } catch (InterruptedException e) {        e.printStackTrace();    }    System.out.println("Thread 2");});t1.start();t2.start();

今天的内容就分享到这儿,喜欢的朋友可以关注,点赞。有什么不足的地方欢迎留言指出,您的关注是我前进的动力!

END


扫码关注

一起积累后端知识
不积跬步,无以至千里
不积小流,无以成江海

喜欢此内容的人还喜欢

谈谈id那些事(五)——美团的 Leaf 的ID生成


一个阿里二面面试官必问的问题


谈谈id那些事(三)——阿里巴巴的 TDDL的ID生成


分享面试:mysql数据库索引失效的情况


面试常被忽略的问题——内存区域划分