Java多线程常考面试题:什么是阻塞式方法,如何唤醒线程?

时间:2025-01-29 08:07:54

大家好!今天给大家带来一篇关于 Java多线程 的面试题讲解。如果你正在为即将来临的Java社招面试做准备,或者你对Java多线程编程有一些疑惑,那这篇文章绝对能帮助你理清思路,提升自己的面试竞争力。我们今天的重点是 阻塞式方法唤醒阻塞线程的方法,以及常见的 notify() 和 notifyAll() 的区别。听起来有点复杂?别担心,我会通过讲故事的方式来帮助大家理解。

故事引入:三个人的协作

想象一下,你和两个朋友一起参与一个小项目——你们要一起搭建一个桥梁模型。每个人的任务是从各自的工作台把材料送到施工现场。为了提高效率,你们设定了一个流程,每个人的工作必须依赖于别人完成的某些任务,大家需要配合得非常默契。

假设有这样的一个场景:

  • 小张:负责搬运原材料。
  • 小李:负责将原材料组装成桥梁的一部分。
  • :负责检查质量,确保桥梁无误。

一开始,三个人的工作是独立的,但随着项目的进行,工作开始有了依赖关系。比如,小李需要从小张那里拿到原材料才能开始组装,而你则需要等小李完成一部分工作后,才能开始质量检查。

这就涉及到一个非常经典的问题:怎么让你们的工作协调得更好? 你们的工作是串联的——一个人的任务完成了,才会触发下一个人的任务。倘若有一个环节被阻塞,整个流程就会被拖慢。为了防止这种情况,你们需要在适当的时候通知对方。

阻塞式方法的引入

你可能会好奇,这和Java线程有什么关系呢?其实,这正是 Java线程中的阻塞式方法 的一个非常生动的类比。阻塞 就像是工作流程中的停滞,每当某个线程遇到需要等待的情况,它就会“阻塞”住,直到满足某个条件,才能继续执行。

什么是阻塞式方法?

在Java中,当一个线程执行阻塞式方法时,它会被挂起,无法继续执行,直到某个条件得到满足才能恢复工作。阻塞的原因有很多种,比如:

  • I/O操作:当线程在执行文件读写、数据库操作、网络请求等I/O操作时,它可能会因为等待响应而被阻塞。
  • 锁竞争:多个线程同时争抢一个共享资源时,某些线程可能会因为无法获得锁而被阻塞,直到其他线程释放锁。
  • 线程等待:线程可能需要等待某个特定的信号或条件,比如等待其他线程完成某项任务,才能继续执行。

你可以把这些阻塞操作想象成桥梁建设中的某个环节无法继续推进,整个团队得停下来,等待一个特定的条件触发才能继续工作。

阻塞的线程是如何恢复的?

那么,问题来了!当一个线程阻塞后,它怎么才能继续执行呢?答案就是 唤醒线程。就像在你和小张、小李的例子中,当小李完成了组装,你就能开始质量检查;而当你检查完质量后,工作又可以继续。

Java中有两种方式可以唤醒一个被阻塞的线程:

  • notify()
  • notifyAll()

线程间的通信:notify() 和 notifyAll()

这两种方法是 Object类 中的成员方法,主要用于线程间的通信,它们的作用是唤醒在当前对象监视器上等待的线程。

notify()

notify() 方法用于唤醒一个在当前对象监视器上等待的线程(如果有多个线程在等待,随机唤醒其中一个)。它会使得该线程从“阻塞”状态转为“就绪”状态,等待CPU分配时间片。换句话说,它就像一个信号,告诉某个被阻塞的线程:“嘿,起来工作吧!你的条件已经满足了!”

回到我们的例子,假设 小李 在完成组装后,调用了 notify(),这个操作就会唤醒一个正在等待的线程,也许是你,也许是小张(随机决定),让它继续进行后续工作。

notifyAll()

与notify()方法不同,notifyAll() 会唤醒所有在当前对象监视器上等待的线程。这意味着,所有被阻塞的线程都会被通知,恢复到“就绪”状态,等待CPU的调度。

这个方法适用于当多个线程可能同时有任务需要处理时(比如多个线程都在等待某个资源)。例如,如果有很多个线程都在等待桥梁模型的原材料,这时候我们就需要用 notifyAll() 来唤醒所有被阻塞的线程,让它们各自去完成工作。

notify() 和 notifyAll()的区别

通过上面的例子,你应该能理解 notify()notifyAll() 的差别了。下面,我们来总结一下:

Java多线程常考面试题:什么是阻塞式方法,如何唤醒线程?_当前对象

代码演示:阻塞与唤醒

现在,让我们通过一段代码来直观地理解 notify() 和 notifyAll() 的使用。假设有两个线程,一个在等待资源,另一个在生产资源。

Java多线程常考面试题:什么是阻塞式方法,如何唤醒线程?_多线程_02

在这个例子中,我们有一个生产者线程和一个消费者线程。生产者负责生成资源,而消费者则负责消费资源。每次消费或生产后,线程会通过 wait() 阻塞自己,直到另一个线程通过 notify() 唤醒它们。

总结

  • 阻塞式方法 是指使线程暂时挂起,直到某个条件满足才恢复执行的操作,比如 wait()。
  • 唤醒阻塞线程 的方法有 notify() 和 notifyAll(),它们分别唤醒一个或所有等待的线程。
  • notify() 和 notifyAll() 的区别在于,notify() 唤醒一个等待线程,而 notifyAll() 会唤醒所有等待线程。它们各自有不同的适用场景。

END

希望通过今天的文章,大家能够更清楚地理解阻塞、唤醒以及 notify() 和 notifyAll() 的区别。记住,面试中的问题不仅考察你的知识深度,也考察你解决问题的能力和思维方式。掌握了这些基础知识,你在面试中一定能够脱颖而出!加油!

如果你对Java多线程还有任何问题,或者希望深入了解更多面试题,欢迎在评论区留言哦~

我是小米,一个喜欢分享技术的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号软件求生,获取更多技术干货!