在Java中断言同步的顺序

时间:2010-10-28 20:27:58

标签: java concurrency synchronization instrumentation

在高度并发的系统中,很难确信您对锁的使用是否正确。具体来说,如果以在另一个线程中以正确顺序获取的顺序获取锁定,则会导致死锁。

有一些工具(例如Coverity)可以对代码库进行静态分析并查找“异常”锁定命令。我想探索满足我需求的其他选择。

是否有用于检测Java代码的轻量级工具,可以检测以预期的顺序获取锁定的情况?我可以通过评论/注释显式调用锁定命令。

首选免费和/或开源解决方案。如果有针对此问题的非仪器方法,请评论。

*就我的目的而言,轻量级意味着......

  • 如果是仪器,我仍然可以使用相同的 ballpark 性能运行我的程序。我想,30-50%的降解是可以接受的。
  • 我不需要花半天时间与工具交互,只是为了让它“好”。理想情况下,我只会注意到在出现问题时我正在使用它。
  • 如果是仪器,则应该很容易为生产环境禁用。
  • 它不应该在每个synchronize语句中混乱我的代码。如前所述,我可以明确地评论/注释被相对排序锁定的对象或对象类。

3 个答案:

答案 0 :(得分:3)

我没有使用过AspectJ,所以无法保证它的易用性。我使用ASM创建了一个自定义代码分析器,这大约是2天的工作。仪器同步的努力应该是类似的。一旦你熟悉方面,AspectJ应该更快更容易。

我已经为基于c ++的服务器实现了死锁检测跟踪。我是这样做的:

  • 当我获取或释放锁定时,我跟踪:
    • <time> <tid> <lockid> <acquiring|releasing> <location in code>
  • 这种额外的痕迹严重影响了性能,无法在生产中使用。
  • 因此,当在生产中发现可能的死锁时,我使用日志文件来弄清楚死锁周围发生了什么。然后在我的跟踪开启的测试环境中重现了此功能。
  • 然后我在日志文件上运行了一个脚本,看看死锁是否可能以及如何进行死锁。我使用了一个awk脚本,使用这个算法:
    • Foreach线
      • 如果获得
        • 将lockid添加到此线程的当前锁列表
        • 将此列表中的每对锁添加到此线程的set lock对。例如,对于Lock A -> Lock B -> Lock C列表,生成对(Lock A, Lock B), (Lock A, Lock C), (Lock B, Lock C)
      • 如果放行
        • 从此帖子的列表尾部删除当前的lockid
    • 对于每个锁对,搜索反向锁对的所有其他线程,每个匹配都是潜在的死锁,因此打印受影响的对和线程
    • 而不是让算法变得更聪明,然后桌面检查锁定获取,看看它是否真的死锁。

我在未能找到死机原因数天之后做到这一点,需要花费几天时间才能实现,并且需要几个小时才能找到死锁。

如果您在Java中考虑这种方法,需要考虑的事项是:

  • 您是否仅使用synchronized来保护您的关键部分?你在java.lang.concurrent中使用这些类吗? (这些可能需要特殊处理/仪器)
  • 使用aspect / ASM打印代码位置有多容易?我在c ++中使用了__FILE____LINE__。 ASM将为您提供类名,方法名和签名。
  • 您无法检测用于保护您的跟踪/记录的锁。
  • 如果您为每个线程使用一个日志文件并为该文件对象设置线程本地存储,则可以简化您的检测。
  • 如何唯一标识您同步的对象?也许toString()和System.identityHashCode()就足够了,但可能需要更多。我在C ++中使用了对象的地址。

答案 1 :(得分:1)

您可以使用AspectJ,它相对容易学习,并允许您设置自己的自定义和简化方式来监控线程及其访问的任何锁。

答案 2 :(得分:0)

不能让你一路走好,但一个好的开始就是使用JCIP annotationsFindBugs抓住一些东西。