我需要跟踪在我的一个对象上获得锁定的所有线程。
当任何线程获得锁定时,是否可以挂钩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?
答案 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