记录在我的对象上获取锁定的所有线程

时间:2014-03-05 12:15:08

标签: java multithreading

我需要跟踪在我的一个对象上获得锁定的所有线程。

当任何线程获得锁定时,是否可以挂钩java中的隐式同步机制并记录线程id(或其他一些信息)?

据我所知,没有办法可以覆盖。我也没有在反射api中找到任何有用的东西。我没有找到任何能够跟踪锁的外部工具(VisualVM跟踪只有cpu和内存使用,FindBugs使用静态分析,javapathfinder似乎只能测试小的非awt应用程序)。

编辑: 似乎有一个非常相似的问题In Java, how to log a message every time a given object's monitor is entered or exited?

4 个答案:

答案 0 :(得分:1)

看起来你最有可能在所有情况下都能正常工作的解决方案(不需要每次使用来调用自定义锁定函数)都是做字节码检测。您可以找到monitorenter和monitorexit的所有情况,并在这些情况下添加您自己的特殊说明。可以提供帮助的两个资源是:http://www.correlsense.com/blog/java-bytecode-instrumentation-an-introduction/(这是一篇包含一些信息的博客文章)和http://commons.apache.org/proper/commons-bcel/manual.html(这是一个可以帮助您的图书馆)。

答案 1 :(得分:0)

我想不出任何办法。您可以轮询ThreadMXBean以找出哪个线程持有哪个锁,但这对您没有帮助,因为无论何时线程获取特定锁,您都无法记录

但是,如果用法使您的IDE可以告诉您所使用的所有位置,则可以将日志语句放在synchronized块中。

如果不这样做,你可能不得不用其他东西替换监视器对象,并在那里有你的跟踪代码。

答案 2 :(得分:0)

如果代码的检测是可接受的,您可以向synchronized块添加“log”语句,该语句将使用Thread.currentThread()来获取当前线程,并使用IdentityHashMap将同步对象与线程名称集合相关联。当然,线程可以具有相同的名称,您可能必须过滤日志调用的执行,这样您就不会被object->线程关联所淹没。

答案 3 :(得分:0)

不幸的是,它只能通过字节码操作来实现。幸运的是,字节码操作并不那么困难(感谢ASM)。

我使用自定义java.lang.instrument.ClassFileTransformer创建了一个java代理,以便在加载时修改类。类加载器拦截所有同步块(它们以MONITORENTER指令开始)和同步方法(它们MONITORENTER指令开始)并插入对跟踪函数的调用这些地点。

因为只要任何线程进入任何同步部分就会调用跟踪函数,它会将锁定对象作为参数,因此我可以决定是否对该对象感兴趣或不

public static void trace(Object lock) {
    if (lock instanceof TraceMe) {
        // Do whatever you want here.
    }
}

可以在此gist中找到代理的代码。将其编译为jar文件并添加以下MANIFEST.MF文件:

Manifest-Version: 1.0
Premain-Class: com.example.LockTracerAgent

使用以下命令运行:

    java -Xbootclasspath/p:asm-4.2.jar:myapp.jar -javaagent:myagent.jar -jar myapp.jar