繁体   English   中英

在java中查找同步争用证据的位置?

[英]Where to look for synchronized contention evidence in java?

我们的Tomcat Web应用程序在被几百个用户使用时感觉很慢。 服务器在托管公司,他们的报告没有显示带宽或CPU工作负载的任何问题,所以我怀疑减速的原因可能是因为我们封装在同步调用下的一些遗留代码的争用,因为它是更容易的路径

我在开发环境中做了一些人工测试,用ThreadLocal解决方案改变了同步调用,它变得更快,但我知道我的老板会要求我一些证据表明它的生产速度也会更快。

我怎么能确定我的应用程序中的线程争用是否存在问题?

我认为最近的Java 6 JDK附带的visualVM工具的线程详细信息视图将能够为您的理论提供(或反对)理论的可靠证据。 它显示每个线程的饼图,显示它在显示器上运行,休眠,等待和等待的时间。 最后一个(以红色显示)是您感兴趣的内容:

替代文字

如果你有一个你认为更快的修改版本,可以使用一些负载测试器(例如JMeter )测试它们来测试两个版本。 如果存在显着差异,您将获得结果证明。

Thare是一堆开源的java profilers ,以及其他可能需要花钱的东西,比如YourKit 您应该使用现有代码和增强代码运行测试。 使用ThreadLocals的工作一般应该减少争用,但是考虑在开始优化之前进行基准测试也很好。

另一个可以在不设置任何探查器的情况下完成的非常简单的测试是在应用程序显得缓慢时进行一些线程转储(ctrl-break或kill -QUIT)。 发现几个线程在相同或相同的监视器上等待很短的时间可能会非常清楚地指出缓慢的点。 您可以使用TDA这样的工具 ,Java线程转储分析器来帮助您梳理线程转储。

再次,在开始优化之前完成这项工作是个好主意。 这是因为,虽然可能有一些明显的地方可以使优化产生影响,但实际的用户行为可能会触发开发人员不考虑的路径,而这些可能会成为真正的问题领域。

jstack PID

将打印出具有进程ID PID的JVM状态列表,以及有关线程状态的信息。

样本输出(摘录):

"AWT-XAWT" daemon prio=10 tid=0x0000000000e5f800 nid=0x476d runnable [0x00007f1a75616000..0x00007f1a75616bf0]
   java.lang.Thread.State: RUNNABLE
    at sun.awt.X11.XToolkit.waitForEvents(Native Method)
    at sun.awt.X11.XToolkit.run(XToolkit.java:543)
    at sun.awt.X11.XToolkit.run(XToolkit.java:518)
    at java.lang.Thread.run(Thread.java:636)

"Java2D Disposer" daemon prio=10 tid=0x0000000000d8b800 nid=0x476c in Object.wait() [0x00007f1a759df000..0x00007f1a759dfc70]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00007f1a82e2c3f8> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:133)
    - locked <0x00007f1a82e2c3f8> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:149)
    at sun.java2d.Disposer.run(Disposer.java:143)
    at java.lang.Thread.run(Thread.java:636)

我还试图隔离争用资源。 例如,如果遗留库锁定到syncrhonize写入数据库,您可能会最小化写入。

我可以在这样的同步调用中添加日志记录

//...
long t0 = System.currentTimeMillis();
synchronized(lockObj){
    logger.info("T sync :" + (t0 - System.currentTimeMillis()));
    //...
}

但这感觉便宜又脏。

你的分析听起来合理。 你可以将visualvm(在JDK中)附加到进程中,这样你就可以看到时间花在哪里了吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM