Java多线程问答

时间:2020-01-09 10:35:22  来源:igfitidea点击:

这篇文章中有Java多线程问题和答案的集合。

Java多线程面试题

  • 什么是多线程?一个程序可以有多个独立运行的子任务,这些子任务被称为线程,而一个程序可以运行许多这样的线程,从而使其成为多线程程序。 Java内置了对多线程编程的支持。在此处阅读有关多线程的更多信息。
  • 多线程有哪些优势?在程序中,我们可以有一个等待某些资源或者事件的任务,而不是使整个程序与该任务绑定并使整个程序无响应,我们可以为该任务创建一个单独的线程,使其可以独立运行。那是多线程的优点之一。通过使多个线程同时运行,CPU使用率是最佳的,并且可以提高应用程序的性能。由于线程是轻量级的并且共享堆内存,因此可以通过多个线程而不是单个线程来执行任何耗时的任务,以通过共享CPU周期而无需使用大量内存来提高吞吐量。在此处阅读有关多线程的更多信息。
  • 用Java如何创建线程? Java中的线程可以通过实现Runnable接口来创建。
  • 通过扩展Thread类。

我们选择这两种方式中的任一种来在Java中创建线程,都需要重写run()方法并提供将在该线程中运行的代码。
在此处阅读有关如何在Java中创建线程的更多信息。

  • 运行创建的线程的过程是什么?一旦有了创建的线程的实例,就在创建的线程对象上调用start方法– thread.start();。

  • 线程启动后,将执行run方法。

  • Java中的线程和进程之间的区别?在并发编程中,有两种类型的多任务处理-基于过程的多任务处理。

  • 基于线程的多任务处理。

流程具有独立的执行环境。进程具有自己的运行时资源,例如内存空间。线程存在于一个进程中-每个进程至少有一个。线程共享进程的资源,包括内存和打开的文件。

进程是在它们自己分配的内存空间中运行的重量级任务。线程是在进程中生成的轻量级线程,并共享其内存。
在此处阅读有关Java中线程与进程之间差异的更多信息。

  • 创建线程的首选方法是-扩展Thread类或者实现Runnable?尽管这两种方法在使用一种方法创建的线程与使用另一种方法创建的线程方面没有什么不同,但是我们必须记住的一件事是Java不支持多重继承,即任何Java类最多可以扩展一类。如果类扩展Thread类来创建线程,则该类不能扩展任何其他类。这是使用Thread类创建线程的缺点之一。
  • 什么是线程生命周期或者Java中不同的线程状态?在Java中创建线程后,线程可以处于以下状态之一:NEW –创建时Java线程处于新状态,但尚未启动RUNNABLE –当start()方法时线程转换为可运行状态在线程对象上被调用。已阻止–正在运行的线程可以在等待监视器锁定时将其状态更改为阻止状态并暂时变为非活动状态。等待–正在运行的线程可以通过调用Object.wait()或者Thread.join()方法进入等待状态。 TIMED_WAITING –当线程使用超时参数调用sleep,wait或者join方法时,该线程处于定时等待状态。 TERMINATED –完成执行的线程进入终止状态。在此处阅读有关Java线程循环的更多信息。
  • 我们如何在Java代码中获取线程状态?我们可以通过在返回Thread.State枚举的线程实例上调用getState()方法来获取Java中的线程状态。在此处阅读有关Java中不同线程状态的更多信息。
  • Java中的线程优先级是什么? Java中的每个线程都有一个优先级分配给它。在Java中创建线程时,它将继承创建线程的优先级。在多线程环境中,线程将获得CPU周期的顺序由线程调度程序确定,并且它使用线程优先级来确定该顺序。在此处阅读有关Java中不同线程优先级的更多信息。
  • Java中的线程优先级范围是多少? Java线程优先级的范围是1到10,其中1是Java中最低的线程优先级,10是最高的线程优先级。在Java Thread类中,有三个静态int字段,用于定义线程的最小,最大和默认优先级。 MAX_PRIORITY –线程可以具有的最大优先级。其值为10. MIN_PRIORITY –线程可以具有的最低优先级。该字段的值为1. NORM_PRIORITY –分配给线程的默认优先级。它的值为5. 在此处了解有关Java中不同线程优先级的更多信息。
  • 如何在Java中更改线程的优先级并检查线程的优先级?创建线程后,可以使用Thread类的setPriority()方法随时更改线程的优先级。如果要检查线程的优先级,可以使用Thread类的getPriority()方法进行检查。
  • 当我们启动任何Java应用程序时,第一个启动的线程是什么?当Java程序启动时,一个线程立即开始运行,该线程在Java中称为主线程。程序中产生的其他线程将从主线程继承某些属性,例如线程优先级,创建的线程是否是守护程序线程。在此处阅读有关Java主线程的更多信息。
  • 什么是Java中的守护程序线程? Java中的守护程序线程是在后台运行的线程,只要该程序在运行,它就可以执行该程序的某些任务。在此处阅读有关Java守护程序线程的更多信息。
  • 如何用Java创建守护线程?守护程序线程创建的任何线程都将自动成为守护程序线程。如果要将线程标记为守护程序线程,可以使用Java中的Thread类的setDaemon(boolean on)方法完成该线程。通过调用setDaemon(true);在线程实例上,我们可以使该线程成为守护线程。在此处阅读有关Java守护程序线程的更多信息。
  • 是否可以在Java中两次启动线程?一个线程只能启动一次,尝试在Java中再次启动同一线程将抛出IllegalThreadStateException。在这里阅读更多关于我们可以在Java中两次启动线程的信息。
  • 如果直接调用线程的run()方法而不是调用start()方法怎么办?如果直接在线程上调用run方法,则实际上不会启动任何新线程。我们在run()方法中编写的逻辑将在当前线程的上下文中执行。在这里阅读更多关于我们可以直接调用run()方法而不是在Java中调用start()方法的更多信息。
  • 我们可以覆盖Java中的start()方法吗?是的,如果我们在调用run()方法之前要执行一些逻辑,则可以在Java中覆盖start()方法。一种条件是,我们应始终从覆盖的start()方法中调用super.start()方法。未能调用super.start()将意味着不会调用run()方法。在此处阅读有关我们可以覆盖Java中的start()方法的更多信息。
  • 什么是多线程中的上下文切换?就多线程而言,上下文切换是将CPU从一个线程切换到另一个线程。当一个线程被抢占执行另一个线程时,被抢占线程的线程状态必须存储在要执行的线程必须恢复其状态的位置。
  • Java多线程中线程间通信如何发生?在Java多线程中,有3种方法可以促进多个线程之间的通信。 wait()方法– wait()方法使持有对象锁的当前线程将自身置于等待状态。
  • notify()方法–唤醒正在该对象的监视器上等待的单个线程。
  • notifyAll()方法–唤醒正在此对象的监视器上等待的所有线程,而不是单个线程。

在此处阅读有关Java中的wait(),notify()和notifyAll()方法的更多信息。

  • 什么是虚假唤醒?等待中的线程可以在不被通知,中断或者超时的情况下唤醒,这称为虚假唤醒。应用程序必须通过在检查线程正在等待的条件的循环中放置对wait()的调用来防范此情况。
synchronized (obj) {
  while ( and ) {
    long timeout = ... ; // recompute timeout values
    int nanos = ... ;
    obj.wait(timeout, nanos);
  }
  ... // Perform action appropriate to condition or timeout
}
  • 使用等待通知方法以Java编写Producer-consumer程序。请参阅此处使用wait-notify方法的Java生产者-消费者程序。
  • 为什么wait(),notify()和notifyAll()方法在Object类中?这些方法wait(),notify()和notifyAll()与与对象关联的锁(监视器)一起使用。持有锁的对象用于线程之间的通信。这就是为什么wait(),notify()和notifyAll()方法位于Object类中的原因。请参见此处为什么对对象类使用wait(),notify()和notifyAll()方法的详细说明。
  • 为什么必须从同步方法或者块中调用Java中的wait(),notify()和notifyAll()方法? wait()方法使当前线程放弃监视并进入等待状态。线程只有在同步上下文中执行时才获取对象的锁。这就是为什么只在同步上下文中使用wait()方法的原因。当调用对象的notify()或者notifyAll()方法时,这是单个线程或者所有线程唤醒并争用监视器的信号。因此notify和notifyAll方法只能从线程在对象上留下锁的位置调用,并且该位置还是同步方法或者块。请参见此处为何必须从同步方法或者块中调用Java中的wait(),notify()和notifyAll()方法的详细说明。
  • Java中的synced关键字有什么作用?在多线程环境中,如果代码中有一个关键部分正在修改共享资源,则我们希望限制对该关键部分的访问,以便在任何给定时间只有一个线程可以访问关键部分代码并使用共享资源。在Java中,实现此过程的过程称为同步,我们将在Java中使用synced关键字进行同步。在此处阅读有关Java中的synced关键字的更多信息。
  • Java中的同步如何工作? Java中的每个对象都有一个与之关联的锁(也称为监视器)。当线程进入同步方法或者同步块时,它将获取该锁。尝试执行相同代码的所有其他线程(在同步方法或者同步块中)必须等待第一个线程完成并释放锁。在此处阅读有关同步如何在Java中工作的更多信息。
  • Java中的同步语句或者同步块是什么?除了同步整个方法外,我们只能同步修改共享资源的方法中的语句(关键部分)。这有助于提高性能,因为线程只能按顺序在同步上下文中执行代码。通过在同步上下文中最小化代码,可以减少顺序执行线程的可能性。在此处阅读有关Java同步块的更多信息。
  • Java中的静态同步是什么?如果同一类的对象不止一个,则两个单独的线程可以获取这两个对象的锁,并同时使用这些单独的锁输入同步方法或者同步块。 Java中的同步,其中同步发生在类级别而不是实例级别。在此处阅读有关Java静态同步的更多信息。
  • 如何确保仅在从主线程开始的其他线程执行完毕后才开始执行主线程?这可以通过在启动的线程上调用join()方法来完成。 join()方法等待,直到调用它的线程终止。在此处阅读有关Java中join()方法的更多信息。
  • 如何检查线程是否仍然存在?通过使用isAlive()方法。此方法测试该线程是否仍然存在。如果线程处于活动状态,则方法返回true,否则返回false。在此处阅读有关Java中isAlive()方法的更多信息。
  • Java中的线程组是什么? Java中的所有线程都属于一个线程组。创建线程后,会将其放入我们指定的线程组中,或者如果未显式指定线程组,则将其放入创建该线程的线程所在的组中。当启动Java应用程序的主线程时,它被放入称为main的组中。在此处阅读有关Java中线程组的更多信息。
  • 如何中断线程?在Java Thread类中,有一个方法interrupt()中断调用线程。在此处阅读有关Java中线程中断的更多信息。
  • 如何暂停正在运行的线程?我们可以使用sleep()方法暂停正在运行的线程。 Java中的Thread.sleep方法使当前正在执行的线程在指定时间段内暂停执行。在此处阅读有关Java睡眠方法的更多信息。
  • 如果在同步上下文中使用sleep()方法调用,休眠线程是否会释放锁?没有线程持有的锁没有被释放。
  • 多线程中的竞争条件是什么?当两个或者多个线程尝试访问共享对象时,Java中的竞争条件可能会发生。如果所有线程都只是读取没有问题的共享对象,但是由于竞争条件,修改或者写入值可能会导致错误的结果。在此处阅读有关Java竞争条件的更多信息。
  • 如何避免Java中的竞争条件?我们需要限制对关键部分的访问,因为我们可以使用同步的方法或者块来同步对关键部分的访问。我们还可以使用并发包中提供的锁的实现。在此处阅读有关Java竞争条件的更多信息。
  • 什么是多线程中的死锁?在多线程环境中,可能会出现这样的情况:一个线程正在等待被另一个线程锁定的资源,该资源又正在等待另一个线程,依此类推,直到此依赖关系循环回到第一个等待线程。因此,所有线程都在互相等待以释放资源以取得任何进一步的进展,并在此过程中永远被阻塞。这种情况在多线程中称为死锁。在此处阅读有关Java死锁的更多信息。
  • 编写Java程序来创建死锁?在此处查看Java程序以创建死锁。
  • 如何在Java中检测死锁或者如何在Java中获取线程转储?为了检测代码中的死锁,我们可以获取应用程序的线程转储并进行分析。我们可以使用jstack实用程序通过提供Java应用程序的pid来获取线程转储。该pid可以通过运行jps命令获得。在此处查看获取线程转储并分析死锁的示例。
  • Java中的yield()方法是什么? yield()方法只是对调度程序的提示,当前线程愿意放弃当前使用的处理器。调度程序也可以忽略此提示。在此处阅读有关Java中yield()方法的更多信息。
  • Java中的ThreadLocal类是什么? Java中的ThreadLocal类提供线程局部变量,其中每个线程都有其自己的,独立初始化的变量副本。这样,我们可以避免共享数据并避免使用同步。在此处阅读有关Java中ThreadLocal类的更多信息。
  • Java中的volatile关键字是什么?将变量声明为易失性可确保始终从主存储器读取变量的值,而不将其缓存。这样可以确保线程不会由处理器缓存过时的值,并且始终从主内存中获取正确的值。在此处阅读有关Java中的volatile关键字的更多信息。
  • 什么是多线程中的线程匮乏?如果线程无法获得对共享资源的常规访问并且无法取得进展,则在多线程中称为线程饥饿。可能存在这样一种情况,其他线程正在通过获取监视器来获得对同步方法或者块的访问,因为只有很少的线程无法获取锁,因此无法访问共享资源。在此处阅读有关Java中线程饥饿的更多信息。
  • 什么是多线程活锁?如果两个或者两个以上线程正忙于彼此响应,并且无法在称为多线程的活锁的过程中取得进一步的进展。如果没有死锁,则不会阻塞活动锁。线程处于活动状态,但是它们忙于彼此响应,因此没有任何进展。在此处阅读有关Java活锁的更多信息。