为何服务器QPS上不去?Java线程调优权威指南
41 个线程被某个锁阻塞了。所报告的方法是栈轨迹中第一个非 JDK 方法,在这个例子中是 GlassFish 的 EJBClassLoader.getResourceAsStream。下一步就是考虑栈轨迹信息,搜索这个方法,看看线程是阻塞到什么资源上了。 在这个例子中,所有线程都被阻塞了,在等待读取同一个 JAR 文件;这些线程的栈轨迹表明,所有调用都来自实例化新 SAX 实例的操作。SAX 解析器可以通过列出应用 JAR 文件中 manifest 文件内的资源来动态定义,这意味着 JDK 必须搜索整个类路径来寻找那些条目,直到找到应用想使用的一个(或者是找不到,回到系统解析器)。因为读取这个 JAR 文件需要一个同步锁,所以所有尝试创建一个解析器的线程最终都会竞争同一个锁,这会极大影响应用的吞吐量。(建议设置 -Djavax.xml.parsers.SAXParserFactory 属性来避免这些查找,原因就在于此。) 更重要的一点是,大量被阻塞的线程会成为影响性能的问题。不管阻塞的根源是什么,都要对配置或应用加以修改,以避免之。 等待通知的线程又是什么样的情况呢?那些线程在等待其他事件发生。它们往往是在某个池中,等待任务就绪(比如,上面输出中的 getTask() 方法在等待请求)这类通知。系统线程会在处理像 RMI 分布式 GC 或 JMX 监控这样的事情,它们以栈中只有 JDK 类这类线程的形式出现在 jstack的输出中。这些条件不一定表明有性能问题;对这些线程而言,等待通知是正常现象。 如果线程正在进行的是阻塞式 I/O 读取(通常是 socketRead0() 方法),也会导致问题。这也会影响吞吐量:线程正在等待某个后端资源回复其请求。这时候应该检查数据库或其他后端资源的性能。 小结 利用系统提供的线程基本信息,可以对正在运行的线程的数目有个大致了解。 就性能分析而言,当线程阻塞在某个资源或 I/O 上时,能够看到线程的相关细节就显得比较重要。 JFR 使得我们可以很方便地检查引发线程阻塞的事件。 利用 jstack,一定程度上可以检查线程是阻塞在什么资源上。 (编辑:晋中站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |