代码之家  ›  专栏  ›  技术社区  ›  Serxipc

在java中何处查找同步争用证据?

  •  3
  • Serxipc  · 技术社区  · 16 年前

    当我们的Tomcat web应用程序被几百个用户使用时,它感觉很慢。服务器在一家托管公司,它们的报告没有显示任何bandwith或cpu工作负载问题,因此我怀疑速度变慢的原因可能是因为我们封装在同步调用下的一些遗留代码存在争用,因为这是一条更容易的路径。

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

    如何确定线程争用是否是我的应用程序中的问题?

    6 回复  |  直到 16 年前
        1
  •  7
  •   Michael Borgwardt    16 年前

    我认为 thread details 最新Java6JDK附带的visualVM工具视图将能够为您的理论提供坚实的证据(或反对)。它为每个线程显示一个饼图,显示它在运行、睡眠、等待和在监视器中花费的时间。最后一个(以红色显示)是您感兴趣的内容:

    alt text

        2
  •  3
  •   Rich Seller    16 年前

    如果您有一个您认为更快的修改版本,请使用一些负载测试仪(例如。 JMeter )测试两个版本。如果有显著差异,你会有结果来证明。

        3
  •  1
  •   Steve B.    16 年前
    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)
    

    我还将尝试隔离争用下的资源。e、 g.如果旧库正在锁定以同步对数据库的写入,则可能需要最小化写入。

        4
  •  1
  •   akf    16 年前

    他们是一群 open source java profilers 在您的支配下,以及其他可能需要花钱的,如 YourKit . 您应该使用现有代码和增强代码运行测试。使用TraceLoad的工作一般应该减少争用,但是在开始优化之前,最好还是做基准测试。

    另一个非常简单的测试可以在不设置任何分析器的情况下完成,即在应用程序运行缓慢时执行一些线程转储(ctrl-break或kill-QUIT)。在短时间内发现几个线程在类似或相同的监视器上等待,可能会非常清楚地指出慢点。你可以用 tools like TDA ,一个Java线程转储分析器,帮助您梳理线程转储。

    同样,在开始优化之前做这项工作是一个好主意。这是因为,虽然可能有一些明显的地方,优化可以产生差异,但实际用户行为可能触发开发人员不考虑的路径,而这些路径可能是真正的问题区域。

        5
  •  0
  •   Thorbjørn Ravn Andersen    16 年前

    你的分析听起来很合理。您是否可以将visualvm(在JDK中)等附加到流程,以便查看时间花在哪里?

        6
  •  0
  •   Serxipc    16 年前

    我可以像这样在我们的同步呼叫中添加日志记录

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