当前位置: 首页 > 面试题库 >

Java阻塞问题:为什么JVM会阻塞许多不同类/方法中的线程?

黄高爽
2023-03-14
问题内容

更新: 这看起来像是内存问题。一个3.8 Gb
Hprof文件表明,发生此“阻塞”时,JVM正在对其堆进行转储。我们的运营团队发现该站点没有响应,进行了堆栈跟踪,然后关闭了实例。我相信他们在堆转储完成之前就关闭了该站点。日志中
没有 错误/异常/问题证据-可能是因为JVM在生成错误消息之前就被杀死了。

最初的问题我们最近遇到了一种情况,该应用程序对最终用户似乎挂起了。在应用程序重新启动之前,我们获得了堆栈跟踪,我发现了一些令人惊讶的结果:在527个线程中,有463个线程的状态为“已阻塞”。

过去
过去,被阻塞的线程通常会遇到以下问题:1)一些明显的瓶颈:例如某些数据库记录锁定或文件系统锁定问题导致其他线程等待。2)所有阻塞的线程都将阻塞相同的类/方法(例如jdbc或文件系统类)

异常数据
在这种情况下,除了应用程序类(包括jdbc和lucene调用)之外,我看到各种类/方法都被阻止,包括jvm内部类,jboss类,log4j等。

问题
是什么会导致JVM阻止log4j.Hierarchy.getLogger,java.lang.reflect.Constructor.newInstance?显然,某些资源“稀缺”,但是哪个资源呢?

谢谢

堆栈跟踪摘录

http-0.0.0.0-80-417" daemon prio=6 tid=0x000000000f6f1800 nid=0x1a00 waiting for monitor entry [0x000000002dd5d000]
   java.lang.Thread.State: BLOCKED (on object monitor)
                at sun.reflect.GeneratedConstructorAccessor68.newInstance(Unknown Source)
                at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
                at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
                at java.lang.Class.newInstance0(Class.java:355)
                at java.lang.Class.newInstance(Class.java:308)
                at org.jboss.ejb.Container.createBeanClassInstance(Container.java:630)

http-0.0.0.0-80-451" daemon prio=6 tid=0x000000000f184800 nid=0x14d4 waiting for monitor entry [0x000000003843d000]
   java.lang.Thread.State: BLOCKED (on object monitor)
                at java.lang.Class.getDeclaredMethods0(Native Method)
                at java.lang.Class.privateGetDeclaredMethods(Class.java:2427)
                at java.lang.Class.getMethod0(Class.java:2670)

"http-0.0.0.0-80-449" daemon prio=6 tid=0x000000000f17d000 nid=0x2240 waiting for monitor entry [0x000000002fa5f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
                at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.register(Http11Protocol.java:638)
                - waiting to lock <0x00000007067515e8> (a org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler)
                at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.createProcessor(Http11Protocol.java:630)


"http-0.0.0.0-80-439" daemon prio=6 tid=0x000000000f701800 nid=0x1ed8 waiting for monitor entry [0x000000002f35b000]
   java.lang.Thread.State: BLOCKED (on object monitor)
                at org.apache.log4j.Hierarchy.getLogger(Hierarchy.java:261)
                at org.apache.log4j.Hierarchy.getLogger(Hierarchy.java:242)
                at org.apache.log4j.LogManager.getLogger(LogManager.java:198)

问题答案:

根据收集的证据,大致按照我尝试的顺序列出了这些内容:

  • 您是否看过 GC行为 ?您是否承受着记忆压力?这可能会导致newInstance()上面的其他一些被阻止。运行VM -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -verbose:gc并记录输出。在故障/锁定时间附近,您是否看到过多的GC时间?
    • 条件可以 重复 吗?如果是这样,请尝试在JVM(-Xmx)中使用不同的堆大小,然后查看行为是否发生了重大变化。如果是这样,请查找内存泄漏或为应用程序适当调整堆大小。
    • 如果以前的操作很困难,并且您没有获得OutOfMemoryError应有的帮助,则可以调整GC可调参数…请参阅JDK6.0 XX选项或JDK6.0 GC Tuning Whitepaper。在专门研究-XX:+UseGCOverheadLimit,并-XX:+GCTimeLimit与相关的选项。(请注意,这些文件的记录不充分,但可能会有用…)
  • 可能会 陷入僵局 吗?仅具有堆栈跟踪摘录,无法在此处确定。在线程被阻塞的监控器状态(相对于它们所保持的状态)中寻找周期。我相信jconsole可以为您做到这一点…(是的,在“线程”选项卡下,“检测死锁”)
  • 尝试进行多次 重复的堆栈跟踪 ,以查找哪些变化与什么保持不变…
  • 对每个表示“已阻止”的堆栈条目进行取证…,然后查找特定的代码行,并确定那里是否有监视器。如果实际购买了监控器,那么确定限制资源应该相当容易。但是,如果没有透明可用的监视器,您的某些线程可能会显示为阻塞,这将更加棘手…


 类似资料:
  • 本文向大家介绍Jquery ajax 同步阻塞引起的UI线程阻塞问题,包括了Jquery ajax 同步阻塞引起的UI线程阻塞问题的使用技巧和注意事项,需要的朋友参考一下 最近做一个项目,遇到了一个问题同步ajax引起的ui线程阻塞问题,下面把我的问题解决过程分享给大家。 事情起因是这样的,因为页面上有多个相似的异步请求动作,本着提高代码可重用性的原则,我封装了一个名为getData的函数,它接收

  • 线程实例的join()方法可用于将一个线程的执行开始“连接”到另一个线程的执行结束,这样一个线程在另一个线程结束之前不会开始运行。如果对线程实例调用join(),则当前运行的线程将阻塞,直到线程实例完成执行 但是如果我有多个线程并且当我在循环内部调用join时。所有线程并行运行。但是根据连接的概念,首先连接的线程应该完成,然后只有主线程才允许连接其他线程。 } 在上面的代码中,如果第一个线程被连接

  • 问题内容: 注意:这不是有关settimeout的复制文章,此处的关键答案是浏览器设计选项。 我开始研究node.js:一个测试异步的简单示例: 一件有趣的事情是,在带有curl的lind命令和浏览器中,它的行为是不同的:在Ubuntu 12.10中,我在两个控制台中使用curl localhost:8080,它们在几乎相同的10个发送中进行响应。 但是,我打开了两个浏览器,几乎同时发出了请求,但

  • 问题内容: 当用户选择在另一个线程中启动阻止进程的菜单项时,我试图在JavaFX 8应用程序中提供反馈。在我的实际应用程序中,它是文件下载,但是通过示例,我使用最少的代码创建了一个测试用例: 它的工作方式如下:当选择“开始”菜单项时,主菜单文本应立即更改为“正在运行…”,然后应附加“完成!”。经过5秒钟的模拟我的文件下载的睡眠。 实际上发生的是,即使我正在使用,在阻止过程完成 后 , 两个 文本更

  • 我不明白为什么webclient会阻止我使用gradle的主要netty线程,以下是它的依赖项: 这个gradle脚本在两个应用程序中都使用。在第一个应用程序中,我执行: 第二个应用程序模拟长响应处理: 我希望呼叫服务不会阻塞主线程,而是会继续处理传入的连接,但直到我收到第一个呼叫的响应(睡眠将起作用),我的下一个连接将挂起等待。 结果:第一个应用程序像tomcat一样工作,只有一个线程 我的问题

  • 我不明白以下几点: 用户级线程需要非阻塞系统调用,即多线程内核。否则,整个进程将在内核中阻塞,即使进程中还有可运行的线程。 内核线程如何处理阻塞系统调用?在用户级线程中,当一个线程进行阻塞系统调用(例如读取)时,为什么其他线程不能继续工作?