在sun.misc.Unsafe.park(本机方法)中等待


77

我的一个应用程序在负载下运行了一段时间后挂起,有人知道是什么会导致jstack中的此类输出:

"scheduler-5" prio=10 tid=0x00007f49481d0000 nid=0x2061 waiting on condition [0x00007f494e8d0000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000006ee117310> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1085)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:807)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1043)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1103)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
        at java.lang.Thread.run(Thread.java:722)

我在挂起的jstack输出中看到了很多。

我大量使用Spring @Async和地图,同步地图和ehcache。

有趣的是,这仅发生在一个应用实例上。另外两个运行得很好。在这种情况下,我还能进行哪些调查以获取更多详细信息?

我发现了这个帖子/programming/23992787/parking-to-wait-for-0xd8cf0070-a-java-util-concurrent-locks-abstractqueueds,但是在我的情况下它不是很有用。


2
那是一个SchedeuledExecutorService,waiting可能在大多数时候都是如此。你应该看看别的地方。在这里等待不会消耗CPU,因此不会引起进一步的性能问题。
约翰·温特2014年

如果我是一名博彩玩家,我将查看您的内存使用情况和GC发生率。
John Vint 2014年

好,谢谢。我启用了GC日志记录,将看到在那里可以找到的内容。
康拉德2014年

1
@JohnVint如果您是一个博彩人,那么在内存使用和GC发生方面您会怀疑什么?我有一个类似的问题
user3607022 2015年

4
@ user3607022 GC Overhead limit reached。这明确表明您的应用存在内存问题。如果您看到了这一点,则意味着旧一代已经足够,无法进行进一步的GC处理了。
John Vint

Answers:


187

unsafe.park与thread.wait几乎相同,除了它使用的是体系结构特定的代码(因此它是“不安全的”)。不安全性不是公开可用的,而是在Java内部库中使用的,在Java内部库中,特定于体系结构的代码将提供明显的优化好处。它在线程池中使用了很多。

因此,要回答您的问题,所有线程正在做的就是等待某件事,实际上并没有使用任何CPU。考虑到原始堆栈跟踪表明您正在使用锁,因此我认为您遇到的情况是死锁一直在发生。

是的,我知道您几乎可以肯定已经解决了这个问题。但是,如果有人用Google搜索sun.misc.unsafe.park,您将是最高的搜索结果之一。我认为回答这个问题可能会帮助其他人了解这种似乎正在使用其所有CPU的方法。


19
之所以停放是因为该线程是an线程池的一部分ExecutorService,并且它正在等待通过诸如之类的方法将某些任务放入工作队列中ExecutorService.submit(...)
哈罗德L

9

从堆栈跟踪中可以明显地看出,ThreadPoolExecutor> Worker线程已启动,并且正在等待任务在BlockingQueue(DelayedWorkQueue)上可用以选择任务并执行。因此,只要获得来自发布者线程的信号。


3

我遇到了类似的问题,并且按照之前的回答(谢谢!),我能够搜索并找到如何正确处理ThreadPoolExecutor终端的程序。

就我而言,这只是解决了我逐渐增加的类似阻塞线程的问题:

  • 我在我的finally子句中使用ExecutorService::awaitTermination(x, TimeUnit)ExecutorService::shutdownNow()(如有必要)。
  • 有关信息,我使用了以下命令来检测线程计数并列出锁定的线程:

    ps -u javaAppuser -L | wc -l

    jcmd`ps -C java -o pid =`Thread.print >> threadPrintDayA.log

    jcmd`ps -C java -o pid =`Thread.print >> threadPrintDayAPlusOne.log

    cat threadPrint * .log | grep“ pool-” | wc -l

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.