Multithreading 如果一个线程调用getStackTrace(),而lambda定义(通过Unsafe.defineAnonymousClass)发生在另一个线程中,Java8将挂起

Multithreading 如果一个线程调用getStackTrace(),而lambda定义(通过Unsafe.defineAnonymousClass)发生在另一个线程中,Java8将挂起,multithreading,lambda,java-8,stack-trace,freeze,Multithreading,Lambda,Java 8,Stack Trace,Freeze,我的Web应用程序运行在Apache Tomcat/8.0.21中,JVM为1.8.0_45-b15,Windows Server 2012运行在16核(32核,含HT)双Xeon NUMA机器上,在某些非常不幸的情况下,当标题中描述的操作同时发生在两个不同的线程中时,它可能会被卡住 执行第一个操作(getStackTrace())的线程正在尝试执行一些诊断,以检测系统的哪个部分在调用thread.dumpThreads时速度减慢并卡住。 另一个线程正在执行一些操作,其中包括JVM部分的幕后la

我的Web应用程序运行在Apache Tomcat/8.0.21中,JVM为1.8.0_45-b15,Windows Server 2012运行在16核(32核,含HT)双Xeon NUMA机器上,在某些非常不幸的情况下,当标题中描述的操作同时发生在两个不同的线程中时,它可能会被卡住

执行第一个操作(
getStackTrace()
)的线程正在尝试执行一些诊断,以检测系统的哪个部分在调用
thread.dumpThreads
时速度减慢并卡住。 另一个线程正在执行一些操作,其中包括JVM部分的幕后lambda定义

特别是,我有以下堆栈跟踪(通过
jstack-F
获得):

在我看来,这个问题可能与
不安全.defineAnonymousClass
无法处理对
java.lang.Thread.dumpThreads
的持续调用有关(反过来,在JVM内实现
java.lang.Thread.getStackTrace
)。关键的一点是,由于
final
或包修饰符,我无法扩展此过程中涉及的任何核心类(例如
查找
方法处理
,等等)为了在调用
java.lang.Thread.dumpThreads
的过程中引入一个锁来阻止棘手的不安全调用。另外,我怀疑引入这样的锁也会让事情慢一些,因为lambda无处不在

有没有人遇到过类似的问题?你能帮我解决吗

谢谢大家!


当然,stacktrace中也有类似的线程,我省略了这些线程,因为我认为它们与本例无关

Thread 154: (state = BLOCKED) [Many of these....]
 - sun.misc.Unsafe.park(boolean, long) @bci=0 (Compiled frame; information may be imprecise)
 - java.util.concurrent.locks.LockSupport.parkNanos(java.lang.Object, long) @bci=20 (Compiled frame)
 - java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(long) @bci=78 (Compiled frame)
 - org.eclipse.jetty.util.BlockingArrayQueue.poll(long, java.util.concurrent.TimeUnit) @bci=57, line=389 (Compiled frame)
 - org.eclipse.jetty.util.thread.QueuedThreadPool.idleJobPoll() @bci=12, line=516 (Compiled frame)
 - org.eclipse.jetty.util.thread.QueuedThreadPool.access$700(org.eclipse.jetty.util.thread.QueuedThreadPool) @bci=1, line=47 (Compiled frame)
 - org.eclipse.jetty.util.thread.QueuedThreadPool$3.run() @bci=300, line=575 (Compiled frame)
 - java.lang.Thread.run() @bci=11 (Compiled frame)


Thread 153: (state = BLOCKED) [and of these...]
 - sun.misc.Unsafe.park(boolean, long) @bci=0 (Compiled frame; information may be imprecise)
 - java.util.concurrent.ForkJoinPool.awaitWork(java.util.concurrent.ForkJoinPool$WorkQueue, int) @bci=354 (Compiled frame)
 - java.util.concurrent.ForkJoinPool.runWorker(java.util.concurrent.ForkJoinPool$WorkQueue) @bci=44 (Interpreted frame)
 - java.util.concurrent.ForkJoinWorkerThread.run() @bci=24 (Interpreted frame)


Thread 141: (state = BLOCKED) [and of these...]
 - sun.misc.Unsafe.park(boolean, long) @bci=0 (Compiled frame; information may be imprecise)
 - java.util.concurrent.locks.LockSupport.park(java.lang.Object) @bci=14 (Compiled frame)
 - java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await() @bci=42 (Compiled frame)
 - java.util.concurrent.LinkedBlockingQueue.take() @bci=29 (Compiled frame)
 - org.apache.tomcat.util.threads.TaskQueue.take() @bci=36, line=103 (Compiled frame)
 - org.apache.tomcat.util.threads.TaskQueue.take() @bci=1, line=31 (Compiled frame)
 - java.util.concurrent.ThreadPoolExecutor.getTask() @bci=149 (Compiled frame)
 - java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) @bci=26 (Interpreted frame)
 - java.util.concurrent.ThreadPoolExecutor$Worker.run() @bci=5 (Interpreted frame)
 - org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run() @bci=4, line=61 (Interpreted frame)
 - java.lang.Thread.run() @bci=11 (Interpreted frame)

最后我设法解决了这个棘手的问题。如果将该选项传递给JVM可执行文件(就像我试图修复的JVM一样),JVM可能会遇到类似于发布的跟踪(至少涉及
sun.misc.Unsafe.defineAnonymousClass
)。出于某种原因,这可能会在Java系统库中激发这种死锁类型的错误,它看起来是随机的(就像所有死锁错误一样),并且随着JVM进程的“老化”越来越有可能。同样,对于死锁bug来说,这并不是什么新鲜事:您将越多的“齿轮”(例如,应该卸载但不是由于该选项而产生的类)放入机器中,它们中的两个或多个就越有可能出现问题

因此,删除选项
-XX:-classdesigning
会使此问题完全消失


底线是:永远不要在生产系统中使用
-XX:-classdownloading
(或者让任何人在JVM进程启动脚本中使用此选项),即使在,然而,由于
sun.misc.Unsafe.defineAnonymousClass中的问题,它仍然会受到严重影响。请同时显示相关代码。
jstack
同时证明可以转储所有堆栈跟踪。@Jagannath,哪种代码?唉,我不能发布产品代码,因为它是客户的财产。然而,我可以告诉你们,第一个线程拥有一个内在锁,但并没有其他线程试图锁定它。事实上,除了两个阻塞线程和Tomcat的工作线程之外,似乎没有其他活动。回到代码,你想从中找出什么样的坏味道?如果你能告诉我你的想法,我可以检查是否是这样。@Holger,事实上我被迫使用
-F
参数来转储堆栈;如果没有
-F
jstack
就无法工作。另外,没有其他工具(如JConsole、JVisualVM、JMC等)能够连接到JVM,这导致了被卡住。@Holger,现在我明白你的意思了。我怀疑在
getStackTrace()
内部调用的所有线程堆栈跟踪的转储遵循不同的路径,而不是在
jstack
内部调用的路径。我将研究后者的细节,试图找出其中的差异。谢谢你的提示!
Thread 154: (state = BLOCKED) [Many of these....]
 - sun.misc.Unsafe.park(boolean, long) @bci=0 (Compiled frame; information may be imprecise)
 - java.util.concurrent.locks.LockSupport.parkNanos(java.lang.Object, long) @bci=20 (Compiled frame)
 - java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(long) @bci=78 (Compiled frame)
 - org.eclipse.jetty.util.BlockingArrayQueue.poll(long, java.util.concurrent.TimeUnit) @bci=57, line=389 (Compiled frame)
 - org.eclipse.jetty.util.thread.QueuedThreadPool.idleJobPoll() @bci=12, line=516 (Compiled frame)
 - org.eclipse.jetty.util.thread.QueuedThreadPool.access$700(org.eclipse.jetty.util.thread.QueuedThreadPool) @bci=1, line=47 (Compiled frame)
 - org.eclipse.jetty.util.thread.QueuedThreadPool$3.run() @bci=300, line=575 (Compiled frame)
 - java.lang.Thread.run() @bci=11 (Compiled frame)


Thread 153: (state = BLOCKED) [and of these...]
 - sun.misc.Unsafe.park(boolean, long) @bci=0 (Compiled frame; information may be imprecise)
 - java.util.concurrent.ForkJoinPool.awaitWork(java.util.concurrent.ForkJoinPool$WorkQueue, int) @bci=354 (Compiled frame)
 - java.util.concurrent.ForkJoinPool.runWorker(java.util.concurrent.ForkJoinPool$WorkQueue) @bci=44 (Interpreted frame)
 - java.util.concurrent.ForkJoinWorkerThread.run() @bci=24 (Interpreted frame)


Thread 141: (state = BLOCKED) [and of these...]
 - sun.misc.Unsafe.park(boolean, long) @bci=0 (Compiled frame; information may be imprecise)
 - java.util.concurrent.locks.LockSupport.park(java.lang.Object) @bci=14 (Compiled frame)
 - java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await() @bci=42 (Compiled frame)
 - java.util.concurrent.LinkedBlockingQueue.take() @bci=29 (Compiled frame)
 - org.apache.tomcat.util.threads.TaskQueue.take() @bci=36, line=103 (Compiled frame)
 - org.apache.tomcat.util.threads.TaskQueue.take() @bci=1, line=31 (Compiled frame)
 - java.util.concurrent.ThreadPoolExecutor.getTask() @bci=149 (Compiled frame)
 - java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) @bci=26 (Interpreted frame)
 - java.util.concurrent.ThreadPoolExecutor$Worker.run() @bci=5 (Interpreted frame)
 - org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run() @bci=4, line=61 (Interpreted frame)
 - java.lang.Thread.run() @bci=11 (Interpreted frame)