前 20 个Java多线程面试问题和答案
Java在 TIOBE 流行的编程开发人员中排名第一,超过 1000 万名开发人员使用了超过 150 亿台支持Java 的设备。它用于为大数据等趋势技术以及手机和 DTH 盒等家用设备创建应用程序,在当今信息时代无处不在。
从面试的角度来看,Core Java(J2SE) 中的多线程是一个非常重要的话题。它可以带领您成为一名Java开发人员、 Java测试工程师、 Java架构师、首席分析师、 Java顾问,最重要的是成为一名真正优秀的Java程序员,使您有信心潜入 J2EE 编程,即Java到企业版或外行语言让您适合直接在企业域工作流中工作。在印度, Java开发人员的福利从300K 到 25000K 不等,根据智力水平不同。
因此,让我们从最常见的Java多线程面试问题开始,并附上他们的详细答案。
Q-1 什么是多任务处理?
多任务操作系统是一种操作系统,可以让您感知同时运行 2 个或更多任务/作业/进程。它通过在这些任务/作业/进程之间划分系统资源并在任务/作业/进程反复执行时在它们之间切换来实现这一点。通常,CPU 一次只处理一个任务,但切换速度如此之快,以至于看起来 CPU 一次正在执行多个进程。它们可以支持抢占式多任务处理,其中操作系统为应用程序提供时间(几乎所有现代操作系统),或者支持协作多任务处理,其中操作系统等待程序交还控制权(Windows 3.x、Mac OS 9 和更早版本),导致挂起和崩溃。多任务处理也称为分时处理,是多道程序设计的逻辑扩展。
多任务编程有以下两种类型:
- 基于进程的多任务处理
- 基于线程的多任务处理
Note: Performing multiple tasks at one time is referred to as multithreading in java which is of two types namely Process-based multithreading and Thread based multithreading.
Q-2 如何识别过程?
任何处于工作状态的程序都称为进程。这些进程确实具有作为单个可调度单元的线程。
Q-3 您如何看待线程?
为了查看线程状态,让我们将 Windows 作为操作系统,它说明然后我们将使用 ProcessExplorer,您可以在其中看到下面显示的 Windows 操作系统的 GUI。
This PC > OS > Users > GeeksforGeeks > Downloads > ProcessExplorer
ProcessExplorer在 windows 操作系统中如下图所示
Note: All of them as listed in the above media are the processes as shown above where at a time many are running in parallel to each other henceforth illustrating multiprocessing in the Jwindows operating system.
正如我们所见,线程确实驻留在单个进程中,因此我们必须深入研究特定进程以查看它们,以便向用户展示后端计算机中的多线程是如何进行的。例如:让我们从上述由各种进程组成的媒体中随机选择一个进程,比如说它是“chrome”。现在我们需要右键单击进程并单击属性菜单。
从上述媒体中,可以清楚地看出chrome是一个进程,在继续执行找出在 chrome 进程内运行的线程的步骤后,我们转到进程“chrome”下面的图形输出的属性,将生成代表在 chrome 进程中运行的线程处理铬。
Note: If we look scroll way from up to down then it will be seeing some colors against a few of those threads. Here green color threads are associated as the newly created threads and red colors associated threads are representing the closed threads.
Note: So for chrome to increase the performance by reducing the response time that is referred to as Thread based multitasking.
Q-4 什么是多线程以及它与多任务有什么不同?
多线程是多任务的一种特殊形式。基于进程的多任务是指同时执行多个任务,其中每个任务都是一个单独的独立进程,是基于进程的多任务。
示例:同时运行Java IDE 和运行 TextEdit。基于进程的多任务由下图表示,如下所示:
基于线程的多任务是指同时执行多个任务,其中每个任务都是称为线程的同一程序的单独独立部分。例如, JUnits使用线程并行运行测试用例。今后,基于进程的多任务是一个更大的场景处理过程,线程处理细节。它已经通过视觉辅助进行了更深入的讨论。
更多细节请参考Java基于进程和基于线程的多任务处理
Q-5 哪种多任务处理更好,为什么?
基于线程的多任务处理更好,因为与进程多任务处理相比,线程的多任务处理需要更少的开销,因为进程是重量级的,反过来需要在内存中拥有自己的单独地址空间,而线程是非常轻量级的进程,并共享相同的地址空间,由重量级进程。
切换是次要原因,因为进程间通信既昂贵又有限。从一个进程到另一个进程的上下文切换成本很高,而线程间通信成本较低,而从一个线程到另一个线程的上下文切换成本较低。
Note: However java programs make use of process-based multitasking environments, but this feature is not directly under Java’s direct control while multithreading is complete.
Q-6 什么是线程?
线程是进程内的轻量级进程。在Java,有两种创建线程的方式,即通过 Thread 类和通过 Runnable 接口。
要了解更多关于此,请参阅在Java线程类,在Java Runnable接口
Q-7 线程有哪些不同的状态,或者线程生命周期是什么?
Java中的线程在任何时间点都处于以下任一状态。一个线程在任何时刻都只处于所示状态之一:
- 新的
- 可运行
- 被封锁
- 等待
- 定时等待
- 已终止
要阅读有关此内容的更多信息,请参阅Java线程的生命周期和状态
Q-8 主线程的任务是什么?
所有Java程序都至少有一个线程,称为主线程,当主线程调用 main() 方法时,JVM 在程序启动时创建它,如伪代码图示的输出所示。
插图:
System.out.println(“Mayank Solanki”);
Output: Mayank Solanki
System.out.println(Thread.getname().currentthread());
Output: main
Q-9 Java哪些不同类型的线程?
Java有两种类型的线程,如下所示:
- 用户线程
- 守护线程
用户线程由Java开发人员创建,例如主线程。默认情况下,在 main() 方法中创建的所有线程都是非守护线程,因为“主”线程是非守护线程。守护线程是在后台运行的低优先级线程,用于执行垃圾收集等任务。当所有用户线程执行完毕后,它们不会阻止守护线程退出。当所有非守护线程完成它们的执行时,JVM 会自行终止。 JVM 不关心线程是否正在运行,如果 JVM 发现正在运行的守护进程线程,它会终止该线程,然后自行关闭。
Q-10 如何创建用户线程?
如前所述,当 JVM 启动时,它会创建一个主线程, 除非用户未创建附加线程,否则程序将运行。 “Main”线程的第一件事是寻找' public static void main(String [] args) '方法来调用它,因为它充当程序的入口点。在 main 中创建的所有其他线程充当“主”线程的子线程。
用户线程可以通过以下两种方式实现:
- 通过扩展Java.lang.Thread 类来使用 Thread 类。
- 通过实现它来使用 Runnable 接口。
Q-11 如何设置线程的名称?
我们可以使用 方法已经在那里被称为setName() 替换默认命名,即“Thread-0”、“Thread-1”等。
thread_class_object.setName("Name_thread_here");
Q-12 什么是线程优先级?
线程中的优先级是一个概念,其中每个线程都有一个优先级,用外行的语言可以说这里每个对象都有优先级,它由 1 到 10 的数字表示。
- 默认优先级设置为 5 作为例外。
- 最低优先级设置为 0。
- 最大优先级设置为 10。
这里定义了 3 个常量,如下所示:
- public static int NORM_PRIORITY
- 公共静态 int MIN_PRIORITY
- 公共静态 int MAX_PRIORITY
要阅读更多相关信息,请参阅Java多线程中的线程优先级
Q-13 死锁如何在多线程中发挥重要作用?
如果我们确实在操作系统中加入了线程,人们就会意识到操作系统中的进程调度算法在深入研究甘特图中加入线程的同一概念。下面列出了一些最流行的,它们总结了所有这些,并在软件开发中得到了实际应用。
- 先进先出
- 后进先出
- 循环调度
现在,想象一下在带有线程的操作系统中死锁的概念,如果人们只对它们有一个概述,那么现在如何在内部计算切换。
Q-14 为什么输出没有顺序?
线程的调度涉及两个边界调度,
- 应用程序开发人员通过轻量级进程 (LWP) 将用户级线程 (ULT) 调度到内核级线程 (KLT)。
- 系统调度程序调度内核级线程以执行不同的独特操作系统功能。
如果多个线程正在等待执行,则线程执行由“ThreadScheduler”决定,它是 JVM 的一部分,因此其供应商依赖于导致意外执行输出顺序。
Note:
- In multithreading, the guarantee of order is very less where we can predict possible outputs but not exactly one.
- Also, note that synchronization when incorporated with multithreading does affect our desired output simply by using the keyword ‘synchronized’.
如下图所示:
Q-15 什么是Java的Daemon Thread 及其属性?
守护线程是一个低优先级的线程,在后台运行,执行垃圾回收等任务。它确实具有以下列出的某些特定属性:
- 当所有用户线程完成执行时,它们无法阻止 JVM 退出。
- 当所有用户线程完成执行时,JVM 会自行终止
- 如果 JVM 发现一个正在运行的守护线程,它会终止该线程,然后自行关闭。 JVM 并不关心 Daemon 线程是否正在运行。
- 这是一个极低优先级的线程
Note: The main difference between user thread and daemon thread is that JVM does not wait for daemon thread before exiting while it do waits for the user thread.
要阅读更多相关信息,请参阅Java的守护线程
Q-16 如何让用户线程成为守护线程?
它是在“线程类”中列出的两个方法的帮助下进行的,它们称为setDaemon()和isDaemon() 。首先,setDaemon() 方法将用户线程转换为守护线程,反之亦然。此方法只能在启动线程之前使用start() 方法调用 else 在启动线程后调用将抛出IllegalThreadStateException在此之后,使用 isDaemon() 方法,如果线程是守护进程则返回布尔值 true 否则返回 false是一个非守护线程。
Q-17 start() 方法的任务是什么?
start() 方法的主要任务是向线程调度程序注册线程,因此可以知道线程调度程序处理的子线程应该执行、何时以及如何调度。次要任务是调用相应的 run() 方法获取线程。
Q-18 start() 和 run() 方法有什么区别?
首先,这两种方法一般都是在线程上操作的。所以如果我们确实使用了 threadT1.start() 那么这个方法将寻找run() 方法来创建一个新线程。而在 theadT1.run() 方法的情况下,将很可能由“主”线程执行正常方法,而不会创建任何新线程。
Note: If we do replace start() method with run() method then the entire program is carried by ‘main’ thread.
Q-19 我们可以重载 run() 方法吗?如果我们不覆盖 run() 方法会怎样?
是的,可以通过向 run() 传递参数来重载 run() 并保持检查以注释掉 run() 方法中的 @override。
它应该与我们没有任何参数的线程一样好,因此重载的实践是对重载的 run() 方法的调用进行注释。现在,如果我们没有重载它,我们需要确认输出是否相同。
如果我们重载了 run() 方法,那么我们将观察到输出始终是 main 方法,这可以从上图的堆栈调用中看出。这是因为如果我们调试下面链接中提供的代码,我们会看到一旦再次调用 start() 方法,就会调用 run(),因为我们没有覆盖 run() 方法。
有关更多信息,请参阅 run() 方法如何重载的实现部分
Conclusion: We can overload the run() method but start() method will call no argument run() only. Hence, it will be of no help to us and is is considered as bad practice.
编译器将简单地执行 Thread 类的 run() 方法,并检查 Thread 类的 run() 方法必须有一个空的实现。因此,它导致没有与线程对应的输出。正如我们上面已经讨论过的,如果我们尝试这样做,那么 Thread 类的 run() 方法将被调用,我们将永远不会得到我们想要的输出。
Note: Geek initially we are requesting to create a thread for us and later the same thread is doing nothing for us which we have created. So it becomes completely meaningless to us by writing unwanted operations to our code fragments. Hence, it becomes useless not to override the run() method.
Q-20 我们可以覆盖 start() 方法吗?
即使我们覆盖自定义类中的 start() 方法,Thread 类也不会为我们进行任何初始化。也不会调用 run() 方法,甚至也不会创建新线程。
Note: We can not restart the same thread again as we will get IllegalThreadStateException from java.lang package. Alongside we can not do this indirectly with usage of ‘super.start()’ method.