无论你是新程序员还是老手,你一定在面试中遇到过线程问题。Java语言的一个重要特性是其对并发的内置支持,这使得Java受到企业和程序员的欢迎。大多数高薪的Java开发职位都要求开发人员精通多线程技术,并且在Java程序开发、调试和优化方面有丰富的经验,因此与线程相关的问题经常在面试中被提及。
在一次典型的Java采访中,采访者将从线程的基本概念开始提问,例如:为什么需要使用线程,如何创建线程,以及如何更好地创建线程(例如继承线程类或调用Runnable接口),然后逐渐询问并发问题,例如在Java并发编程过程中遇到了什么挑战,Java内存模型,JDK1.5中引入了什么高级并发工具,并发编程的常见设计模式,以及经典的多线程问题,例如生产者和消费者、哲学家就餐、读者或简单的有界缓冲区问题仅仅知道线的基本概念是不够的。您必须知道如何处理并发问题,如死锁、竞争条件、内存冲突和线程安全。凭借这些技能,您可以轻松处理多线程和并发面试。
许多Java程序员通常只在面试前看面试问题。因为收集面对面的问题和练习需要时间,所以我从许多面试官那里收集了50个与Java多线程和并发性相关的热门问题。我只收集了相对较新的面试问题,没有提供所有的答案。我认为你足够聪明,已经知道这些问题了。如果你有任何你不明白的问题,你可以用谷歌找到答案。如果你真的找不到答案,你可以在文章的评论中向我寻求帮助。你也可以在这里找到一些答案,Java线程问答前12名下面的
50个Java线程面试问题
是与Java线程相关的常见面试问题,您可以用它们来准备面试。
1)什么是线程?
线程是操作系统可以调度操作的最小单元。它包含在流程中,是流程中的实际业务实体程序员可以用它来进行多处理器编程,你也可以用多线程来加速计算密集型任务。例如,如果一个线程需要100毫秒来完成一个任务,那么用10个线程完成一个变更任务只需要10毫秒。Java在语言层面上为多线程提供了极好的支持,这也是一个很好的卖点。
2)线程和进程之间有什么区别?
线程是进程的子集。一个进程可以有许多线程,每个线程并行执行不同的任务。不同的进程使用不同的内存空间,所有线程共享相同的内存空间。不要把它和堆栈内存混淆。每个线程都有单独的堆栈内存来存储本地数据。如何在Java中实现线程化?
在语言层面有两种方式java.lang.Thread类的实例是一个线程,但是它需要调用java.lang.Runnable接口来执行。由于线程类本身就是调用的Runnable接口,所以您可以继承java.lang.Thread类,或者直接调用Runnable接口来重写运行方法以实现线程。
4)可运行还是线程?
是上述问题的后续。众所周知,我们可以通过继承线程类或调用Runnable接口来实现线程。问题是,哪种方法更好?何时使用它?如果您知道Java不支持类的多重继承,但是允许您调用多个接口,那么这个问题很容易回答所以如果你想继承其他类,当然,调用Runnable接口在
6)线程类中,启动和运行方法有什么区别?问题
经常被问到,但它仍然可以区分面试官对Java线程模型的理解和这个问题。start方法用于启动新创建的线程,run方法在start内部调用,这不同于直接调用run方法。当您调用run方法时,它将仅在原始线程中被调用,并且start方法将仅在没有新线程被启动的情况下启动新线程。
7)在Java中,Runnable和Callable有什么区别?
Runnable和Callable都表示要在不同线程中执行的任务自JDK1.0以来,可运行程序就一直可用,并且在JDK1.5中添加了可调用程序它们之间的主要区别在于,Callable的调用方法可以返回值并抛出异常,而Runnable的运行方法没有这些函数可调用的可以返回一个加载了计算结果的未来对象我的博客有更详细的说明(http://java 67 . blogspot . com/2013/01/difference-between-callable-and-runnable-Java . html)
8)在Java中,CyclicBarrier和CountDownLatch有什么不同?
CyclicBarrier和CountDownLatch都可以用来让一组线程等待其他线程。与循环屏障不同,CountdownLatch不能重复使用。单击此处了解更多信息和示例代码(http://java reviewed.blogspot.com/2012/07/cyclical barrier-example-java-5-concurrency-tutorial.html)
9)什么是Java内存模型?
Java内存模型指定并指导Java程序在不同的内存体系结构、CPU和操作系统之间具有确定性行为这在多线程的情况下尤其重要。Java内存模型保证了对一个线程所做的更改可以被其他线程看到,并且它们是预先关联的。这种关系为程序员定义了一些规则,以便在并发编程时更清晰地思考。例如,先行关系确保
线程中的代码可以按顺序执行,这被称为程序顺序规则。对于同一个锁,解锁操作必须在随后的另一个锁定操作之前发生,也称为管道端锁定规则。在对易失性的后续读操作之前,对易失性的先前写操作也被称为易失性变量规则。线程内的任何操作都必须跟随线程的开始调用,也称为线程开始规则。线程的所有操作都将在线程终止之前终止规则。对象的终止操作必须在对象构造后完成,这也称为对象终止规则。可移植性我强烈建议您阅读《Java并发编程实践》第16章,以加深您对Java内存模型的理解
10)Java中的可变变量是什么?
volatile是一个特殊的修饰符,只能由成员变量使用当Java并发程序缺少同步类时,对成员变量的多线程操作对其他线程是透明的。易失性变量可以确保下一个读操作将在前一个写操作之后发生,这是前一个问题的易失性变量规则。查看有关volatile的更多信息(http://Java reviewed . blogspot . com/2011/06/volatile-keyword-Java-example-tutorial . html)什么是线程安全?向量是线程安全类吗?
如果您的代码处于多个线程同时运行的进程中,这些线程可能会同时运行此代码如果每次运行的结果与单个线程的结果相同,并且其他变量的值与预期的相同,那么它就是线程安全的。如果线程安全计数器类的同一个实例对象被多个线程使用,将不会有计算错误。显然,您可以将集合类分为两类,线程安全的和非线程安全的Vector使用同步来实现线程安全,而类似于Vector的ArrayList并不安全。
12)在Java中什么是竞争条件?举个例子来说明
竞争条件将导致并发程序中的一些错误当多线程竞争一些资源时,就会出现竞争情况。如果第一个要执行的程序未能竞争,后来被执行,那么整个程序中就会出现一些不确定的错误。这种错误很难找到,并且会因为线程之间的随机竞争而重复出现。一个例子是无序处理,详见答案。(http://java reviewed . blogspot . com/2012/02/what-is-race-condition-in . html)
13)如何停止Java中的线程?
Java提供了丰富的API,但没有提供停止线程的APIJDK 1.0最初有一些控制方法,例如停止、暂停和恢复,但是由于潜在的死锁威胁,它们在随后的JDK版本中被丢弃。在那之后,Java API设计者没有提供一个兼容的线程安全的方法来停止一个线程。当run或call方法完成执行时,线程将自动结束。如果您想要手动结束一个线程,您可以使用易失性布尔变量来退出run方法的循环,或者取消中断该线程的任务。单击此处查看示例代码(http://Java reviewed . blogspot . com/2011/10/how-to-stop-thread-Java-example . html)
14)当线程异常运行时会发生什么?
这是我在采访中遇到的一个非常棘手的Java问题。简单地说,如果没有捕获到异常,线程将停止执行。线程。未捕获的异常处理程序是一个嵌入式接口,用于处理由未捕获的异常引起的突然线程中断当未处理的异常将导致线程中断时,JVM将使用线程。GetUncaughtExceptionhandler查询线程的UncathException处理程序,并将线程和异常作为参数传递给处理程序的UncathException方法进行处理。
15)如何在两个线程之间共享数据?
您可以通过共享对象或使用并发数据结构(如阻塞队列)来实现这一点本教程“Java线程间通信”(涉及在两个线程之间共享对象)使用等待和通知方法实现了生产者-消费者模型
16)在Java中,通知和通知所有的区别是什么?
这是另一个棘手的问题,因为多线程可以等待单个监视器锁定。Java API设计者已经提供了一些方法来通知他们等待条件改变,但是这些方法还没有完全实现。notify方法无法唤醒特定的线程,因此它只在只有一个线程在等待时才有用。NotifyAll唤醒所有线程,并允许它们竞争锁,以确保至少有一个线程可以继续运行。
17)为什么等待、通知和通知所有方法不包括在线程类中?
是一个与设计相关的问题,它考察了受访者对现有系统和一些常见但似乎不合理的东西的看法。回答这些问题时,您应该解释为什么将这些方法放在对象类中是有意义的,为什么不在线程类中。一个明显的原因是,JAVA提供的锁是对象级的,而不是线程级的,每个对象都有一个通过线程获得的锁。如果线程需要等待一些锁,那么在对象中调用wait方法是有意义的。如果等待方法是在线程类中定义的,那么线程在等待哪个锁就不明显了。简单地说,因为等待、通知和通知都是锁级操作,所以它们是在对象类中定义的,因为锁属于对象。
18)什么是线程局部变量?
线程本地是Java中的一个特殊变量每个线程都有一个线程本地,也就是说,每个线程都有自己的独立变量,竞争条件完全消除了。对于创建昂贵的对象来说,这是获得线程安全性的好方法。例如,您可以使用线程本地使简单日期格式线程安全。因为该类创建成本很高,并且需要为每个调用创建不同的实例,所以不值得在本地使用它。如果您为每个线程提供一个唯一的变量副本,将会大大提高效率。首先,重用减少了创建的昂贵对象的数量第二,您可以在不使用昂贵的同步或不变性的情况下获得线程安全性。线程局部变量的另一个很好的例子是ThreadLocalRandom类,它减少了在多线程环境中创建的昂贵的随机对象的数量。什么是未来任务?Java并发程序FutureTask中的
表示可以取消的异步操作它有启动和取消操作、查询操作是否完成和检索操作结果等方法。只有当操作完成时,才能检索结果。如果操作未完成,get方法将被阻止。未来任务对象可以用可调用和可运行对象包装。因为FutureTask也调用可运行接口,所以它可以提交给执行器执行。
20)在Java中,中断方法和isInterruptedd方法有什么区别?
中断和isInterrupted的主要区别是前者清除中断状态,而后者不清除Java多线程的中断机制是通过内部标识来实现的。调用线程中断来中断线程会将中断标识设置为真当一个中断线程调用静态方法线程中断来检查中断状态时,中断状态被清除非静态方法isInterrupted用于在不改变中断状态标识的情况下查询其他线程的中断状态。简而言之,任何抛出中断异常的方法都会清除中断状态在任何情况下,一个线程的中断状态都可能被调用中断的其他线程改变。
21)为什么需要在同步块中调用等待和通知方法?
主要是因为Java API要求这样做。如果不这样做,您的代码将抛出一个IllegalMonitorStateException异常另一个原因是避免等待和通知之间的竞争。
22)为什么要检查循环中的等待条件?等待
的线程可能会收到错误警报和错误唤醒。如果循环中没有检查等待条件,程序将在不满足结束条件的情况下退出。因此,当等待线程醒来时,不能认为其原始等待状态仍然有效。它可能会在notify方法调用之后和等待线程唤醒之前发生变化。这就是为什么等待方法在循环中工作得更好。您可以在Eclipse中创建模板来调用wait和notify并尝试一下。如果您想了解更多关于这个问题的信息,我建议您阅读有效Java中的线程和同步章节。
23)在Java中同步集和并发集有什么区别?
同步集和并发集都为多线程和并发提供了合适的线程安全集,但并发集具有更高的可伸缩性。在Java1.5之前,程序员只使用同步集,这将在多线程并发时导致争用,从而阻碍系统的可伸缩性。Java5引入了并发集合,如ConcurrentHashMap,它不仅提供了线程安全性,还通过锁分离和内部分区等现代技术提高了可伸缩性。
24)在Java中堆和栈有什么区别?为什么
将这个问题分为多线程和并发问题?因为堆栈是与线程密切相关的存储区域每个线程都有自己的堆栈内存,用于存储本地变量、方法参数和堆栈调用。存储在一个线程中的变量对其他线程不可见。堆是所有线程共享的公共内存区域。对象都是在堆中创建的。为了提高效率,线程将从堆中获取一个缓存到自己的堆栈中。如果多个线程使用这个变量,可能会出现问题。这时,易变变量可以发挥作用。它需要线程从主内存中读取变量值。
25)什么是线程池?为什么要用它?
需要昂贵的资源和时间来创建线程。如果任务到来并创建了线程,响应时间将会更长,并且进程可以创建的线程数量是有限的。为了避免这些问题,当程序启动时,创建几个线程来响应处理。它们被称为线程池,其中的线程被称为工作线程。从JDK1.5开始,Java API提供了一个执行器框架,允许您创建不同的线程池例如,一个线程池一次处理一个任务。固定数量的线程池或缓存线程池(一种可扩展的线程池,用于具有许多短期任务的程序)
26)如何编写代码来解决生产者和消费者问题?
实际上,您解决的许多线程问题都属于生产者-消费者模型,也就是说,一个线程的生产任务由其他线程消费。您必须知道如何在线程之间进行通信来解决这个问题底层方法是使用等待和通知来解决这个问题,更好的方法是使用信号量或阻塞队列来实现生产者-消费者模型。
27)如何避免死锁?
Java多线程中的死锁
死锁是指在执行过程中,两个或两个以上的进程为争夺资源而相互等待的现象。没有外力,它们就不能向前推进。这是一个严重的问题,因为死锁会使您的程序挂起,并且无法完成任务。死锁必须满足以下四个条件:
互斥条件:一个资源一次只能被一个进程使用请求和保留条件:当一个进程被资源请求阻塞时,它会保留已获得的资源。不可否认的条件:通过这一过程获得的资源不能被强行剥夺,直到它们被用尽。循环等待条件:一个循环等待资源关系是在几个进程之间端到端形成的。避免死锁最简单的方法是停止循环等待条件,设置标志位并对系统中的所有资源进行排序,并规定所有申请资源的进程必须按一定的顺序(升序或降序)运行以避免死锁。在
28) Java中,活锁和死锁有什么区别?
这是上述问题的延伸。活锁类似于死锁,只是活锁中线程或进程的状态不断变化。活锁可以被认为是一种特殊的饥饿。活锁的一个真实例子是两个人在一条狭窄的走廊里相遇。他们两个都试图避开对方,这样他们就可以穿过对方,但是因为避开的方向是一样的,最后没有人可以穿过走廊。简而言之,活锁和死锁的主要区别在于,前一个进程的状态可以改变,但不能继续执行。
29)如何检测线程是否有锁?
直到我参加了一次电话面试,我才知道我们真的可以检查一个线程是否有锁。在java.lang.Thread中,有一个名为holdsLock的方法,当且仅当当前线程在特定对象上有锁时,该方法才返回true
30)如何在Java中获得线程堆栈?
对于不同的操作系统,有许多方法可以获得Java进程的线程堆栈当您获得线程堆栈时,JVM会将所有线程的状态保存到日志文件或输出到控制台。在Windows中,你可以使用Ctrl+Break来获得线程堆栈,在Linux中,你可以使用kill -3您也可以使用jstack来获取它。它对线程id进行操作。您可以使用jps来查找id
31)用于控制线程堆栈大小的JVM中哪个参数是
的问题很简单。-Xss参数用于控制线程的堆栈大小您可以查看JVM配置列表来了解更多关于这个参数的信息。
32)在Java中同步和重入锁有什么区别?
Java在过去很长一段时间里只能通过同步关键字来实现互斥,这有一些缺点。例如,您不能在锁外扩展方法或块边界,并且在试图获取锁时不能中途取消,等等。Java 5通过锁接口提供了更复杂的控制来解决这些问题ReentrantLock类实现了锁,它具有与同步相同的并发性和内存语义,并且还具有可伸缩性。
33)有三个线程T1、T2、T3。您如何确保它们按顺序执行?
有许多方法可以让线程在多线程中以特定的顺序执行。您可以使用thread类的join方法在一个线程中启动另一个线程,另一个线程完成该线程以继续执行。为了确保三个线程的顺序,您应该首先启动最后一个线程(T3调用T2,T2调用T1),这样T1将首先完成,T3将最后完成。屈服方法在
34)线程类中的作用是什么?
Yield方法可以暂停当前正在执行的线程对象,并允许具有相同优先级的其他线程执行。这是一种静态方法,只能确保当前线程放弃占用CPU,但不能确保其他线程可以占用CPU。线程执行产量可以在进入暂停状态后立即执行。
35)什么是Java中并发哈希映射的并发性?
ConcurrentHashMap将实际映射分成几个部分,以实现其可伸缩性和线程安全性该分区是通过使用并发性获得的,并发性是ConcurrentHashMap类构造函数的可选参数。默认值为16,因此在多线程的情况下可以避免争用。要了解更多关于并发和内部大小调整的信息,请阅读我的文章《并发哈希表在Java中是如何工作的》
36)什么是旗语?信号量在
Java中是一个新的同步类,它是一个计数信号从概念上讲,信号量维护一组权限如有必要,在许可证可用之前阻止每次获取,然后获取许可证。每个版本都添加了一个许可证,这可能会释放一个阻止收购者。但是,信号量并不使用实际的许可证对象,而是只计算可用许可证的数量并采取相应的措施信号量通常用在多线程代码中,例如数据库连接池。
37)如果提交任务时线程池队列已满会议上会发生什么?
是一个棘手的问题,许多程序员认为这个任务会一直阻塞,直到线程池队列为空。事实上,如果一个任务不能被调度执行,线程池执行器的提交方法将抛出一个RejectedExecutionException
38)在Java线程池中提交和执行方法有什么区别?这两个
方法都可以向线程池提交任务。execute方法的返回类型是void,它在Executor接口中定义,而submit方法可以返回保存计算结果的Future对象,它在ExecutorService接口中定义,扩展了Executor接口。其他线程池类,如线程池执行器和调度线程池执行器都有这些方法。
39)什么是阻断方法?
阻塞方法意味着程序将等待该方法完成,而不做任何其他事情。服务器套接字的接受方法是等待客户端连接。这里的阻塞意味着当前线程将被挂起,直到返回调用结果,并且在获得结果之前不会返回。此外,还有在任务完成之前返回的异步和非阻塞方法
40)回转螺纹安全吗?为什么?
你当然可以给出一个答案,Swing不是线程安全的,但是你应该解释这个答案的原因,即使面试官没有问你为什么当我们说swing不是线程安全的时候,我们经常提到它的组件。这些组件不能在多线程中修改。对图形用户界面组件的所有更新必须在AWT线程中完成。Swing提供同步和异步回调方法进行更新。
41)在Java中,invokeAndWait和invokeLater有什么区别?这两种方法
由Swing应用编程接口提供给Java开发人员,用于从当前线程而不是事件调度线程更新图形用户界面组件它同步图形用户界面组件的更新,例如进度条。一旦进度被更新,进度条应该相应地改变。如果进程被多个线程跟踪,调用invokeAndWait方法来请求事件调度线程相应地更新组件invokeLater方法异步调用更新组件在
42) Swing API中,哪些方法是线程安全的?
还提到了挥杆和螺纹安全。虽然组件不是线程安全的,但是有一些方法可以被多线程安全地调用,比如重画、重新验证。jtextcomponent的setText方法和JTextComponent的插入和追加方法也是线程安全的
43)如何在Java中创建不可变对象?
似乎与多线程无关,但不变性有助于简化复杂的并发程序。不可变对象可以在没有同步的情况下共享,从而减少了并发访问对象时的同步开销。然而,Java没有@不可变的注释符号。要创建不可变类,必须实现以下步骤:通过构造方法初始化所有成员,不为变量提供setter方法,并声明所有成员为私有,因此不允许直接访问这些成员。在getter方法中,不直接返回对象本身,而是克隆对象并返回对象的副本我的文章《如何在java中使一个对象不变》有详细的教程,在那之后你可以放心了。
44)什么是java中的读写锁?
一般来说,读写锁是锁分离技术用于提高并发程序性能的结果Java中的读写锁是Java 5中新增的一个接口。一个读写锁维护一对关联锁,一个用于只读操作,一个用于写操作。如果没有写线程,读锁可能同时由多个读线程持有写锁是排他的。您可以通过在JDK使用可重入读写锁来实现这个规则。它最多支持65535个写锁和65535个读锁
45)多线程中的繁忙周期是什么?
繁忙周期意味着程序员使用周期使线程等待,不像传统方法等待、睡眠或让步,它们都放弃了CPU控制,而繁忙周期不放弃CPU,它运行的是一个空周期这样做的目的是保持CPU缓存。在多核系统中,当一个等待线程醒来时,它可能会在另一个内核上运行,这将重建缓存。为了避免重建缓存并减少重建等待时间,可以使用它。
46)易变变量和原子变量之间有什么区别?
这是个有趣的问题首先,可变变量和原子变量看起来非常相似,但是它们的功能不同。可变变量可以确保先行关系,即写操作将在后续读操作之前发生,但它不能保证原子性。例如,如果用volatile修改count变量,count++操作不是原子的。AtomicInteger类提供的原子方法可以使这个操作原子化。例如,getAndIncrement方法可以将当前值自动递增1,其他数据类型和引用变量也可以执行类似的操作。
47)如果同步块中的线程抛出异常会发生什么?问题
让许多Java程序员陷入困境。如果你能想到锁是否会释放这个线索来回答,你仍然希望它是正确的。无论您的同步块是正常退出还是异常退出,里面的线程都会释放锁,所以我更喜欢同步块而不是锁接口,因为它不需要我花费精力来释放锁,并且这个功能可以通过在最终块中释放锁来实现。
48)什么是单例模式中的双重检查锁?
在Java面试中经常被问到,但是面试官对回答这个问题的满意度只有50%一半的人不会写双重检查锁,一半的人无法解释它的隐患以及Java1.5如何纠正它。这实际上是一个创建线程安全单例的老方法。当第一次创建单例实例时,它试图用单个锁来优化性能。然而,由于它的复杂性,它在JDK1.4中失败了,我个人也不喜欢它。无论如何,即使你不喜欢它,你仍然需要知道它,因为它经常被问到有关更多信息,您可以查看本文“singleton上的双重检查锁定是如何工作的”。
49)如何用Java创建线程安全的单例?
这是对上述问题的跟进。如果您不喜欢双重锁定,并且访问者要求使用另一种方法来创建单例类,那么您可以通过使用JVM的类加载和静态变量初始化功能来创建单例实例,或者通过使用枚举类型来创建单例实例。我非常喜欢这种方法。
50)按照
编写3个多线程最佳实践,这是我最喜欢的问题。我相信您在编写并发代码时会遵循一些最佳实践来提高性能。我认为大多数Java程序员应该遵循以下三个最佳实践:
给你的线程一个有意义的名字这使得找到或追踪bug变得很容易。orderprocessor、quoteprocessor或tradeprocessor的名称比Thread-1好得多。线程2和线程3。给一个线程一个与其要完成的任务相关的名字。所有主要框架甚至JDK都遵循这种最佳实践。避免锁定和缩小同步范围。锁很昂贵,上下文切换需要更多的时间和空间。尽量减少使用同步和锁定来缩小关键区域。因此,与同步方法相比,我更喜欢同步块,这给了我对锁的绝对控制。多用途同步类使用较少的等待和通知。首先,递减计数锁存器、信号量、循环屏障和交换器这些同步类简化了编码操作,而等待和通知很难控制复杂的控制流其次,这些类是由以下JDK最好的企业编写和维护的。它们将不断优化和完善。使用这些高级同步工具,可以轻松优化您的程序。多用途并发集和较少同步集这是另一个易于遵循且受益匪浅的最佳实践。并发集比同步集具有更好的可扩展性,因此在并发编程中使用并发集更有效。如果您下次需要使用映射,您应该首先考虑使用ConcurrentHashMap。我的文章Java并发集合有更详细的说明51)如何强制线程开始?
就像如何强制进行Java垃圾收集。还没有方法。虽然您可以使用System.gc进行垃圾收集,但不能保证成功。没有办法强迫线程在Java中启动,它是由线程调度器控制的,Java不发布相关的API。
52)什么是Java中的分叉连接框架?
工作连接框架是出现在JDK7中的一个有效工具,通过它,Java开发人员可以充分利用现代服务器上的多处理器它是专门为那些可以递归地分成许多子模块的模块而设计的。目的是利用所有可用的处理能力来提高程序的性能。fork join框架的一大优势是它使用了工作窃取算法,能够完成更多任务的工作线程可以从其他线程窃取任务来执行它们。
53)在Java多线程中调用等待和睡眠方法有什么区别?在
Java程序中等待和睡眠会导致某种形式的暂停,这可以满足不同的需求等待方法用于线程间通信。如果等待条件为真,其他线程被唤醒,它将释放锁,而睡眠方法仅释放CPU资源或停止当前线程执行一段时间,但不会释放锁。超过
是50个流行的Java多线程和并发面试问题我没有分享所有问题的答案,但为未来的读者提供了足够的提示和线索来找到答案。如果你真的找不到问题的答案,请联系我,我会添加它。这篇文章不仅可以用来准备面试,还可以用来检查你对线程问题的理解,比如多线程、并发、设计模式和竞争条件、死锁和线程安全。我打算将本文中的问题汇集成一大堆Java多线程问题,但是没有您的帮助,恐怖是无法完成的。你也可以和我分享任何其他问题,包括那些你已经被问到但还没有找到答案的问题。这篇文章对初学者或有经验的Java开发人员非常有用,您将在两三年甚至五六年后再次阅读它。它对初学者特别有用,因为它可以扩展他们的知识。我会不断更新这些问题。每个人都可以在文章后面的评论中提问,分享和回答问题,以完善这个面对面的问题。