【问题标题】:WAITING at sun.misc.Unsafe.park(Native Method)在 sun.misc.Unsafe.park 等待(本机方法)
【发布时间】:2014-08-06 03:20:16
【问题描述】:

我的一个应用程序在负载下运行一段时间后挂起,有谁知道什么可能导致 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。

有趣的是,这只发生在其中一个应用实例上。另外两个运行良好。 在这种情况下,我还能调查什么以获得更多详细信息?

我发现这篇文章 https://stackoverflow.com/questions/23992787/parking-to-wait-for-0xd8cf0070-a-java-util-concurrent-locks-abstractqueueds 但对我来说不是很有用。

【问题讨论】:

  • 这是一个 ScheduledExecutorService,可能大部分时间都是waiting。你应该看看别的地方。此处的等待不会消耗 CPU,因此不会导致进一步的性能问题。
  • 如果我是赌徒,我会看看你的内存使用情况和 GC 发生率。
  • 好的,谢谢。我启用了 GC 日志记录,看看我能在那里找到什么。
  • @JohnVint 如果你是一个赌徒,你会怀疑内存使用和 GC 发生率是什么?我也有类似的问题
  • @user3607022 GC Overhead limit reached。这清楚地表明您的应用程序存在内存问题。如果你看到了,这意味着老年代已经被填满了,不能再被 GC 了。

标签: java multithreading concurrency java.util.concurrent


【解决方案1】:

unsafe.park 与 thread.wait 几乎相同,除了它使用的是特定于架构的代码(因此它是“不安全”的原因)。 unsafe 不公开提供,但在 Java 内部库中使用,其中特定于体系结构的代码将提供显着的优化优势。它被大量用于线程池。

所以,回答你的问题,所有线程都在等待某事,它并没有真正使用任何 CPU。考虑到您的原始堆栈跟踪显示您正在使用锁,我会假设您的情况正在发生死锁。

是的,我知道您现在几乎可以肯定已经解决了这个问题。但是,如果有人用谷歌搜索 sun.misc.unsafe.park,那么您就是最佳结果之一。我认为回答这个问题可能有助于其他人试图理解这种似乎正在使用他们所有 CPU 的方法。

【讨论】:

  • 因为这个线程是ExecutorService的线程池的一部分,所以它被停住了,它正在等待通过ExecutorService.submit(...)之类的方法将一些任务放到工作队列中。跨度>
  • 它是否也表明它正在等待来自连接的响应?喜欢后端调用?
  • @NithinSatheesan 这似乎是合理的。最好的了解方法是查看堆栈跟踪,看看是谁在调用它。
  • @dsollen 堆栈跟踪与此处的帖子相同。它只是从 Thread.run 开始,到 Unsafe.park 结束。
【解决方案2】:

从堆栈跟踪中可以清楚地看出,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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-07
      • 2018-04-05
      • 2018-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多