在Java中断言同步的顺序

Der*_*ice 14 java concurrency instrumentation synchronization

在高度并发的系统中,很难确信您对锁的使用是否正确.具体而言,如果以在另一个线程中以正确顺序获取时未按预期的顺序获取锁,则可能导致死锁.

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

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

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

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

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

iai*_*ain 3

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

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

  • 当获取或释放锁时,我追踪到:
    • <time> <tid> <lockid> <acquiring|releasing> <location in code>
  • 这个额外的跟踪极大地影响了性能,并且在生产中无法使用。
  • 因此,当在生产中发现可能的死锁时,我使用日志文件来找出死锁周围发生的情况。然后在打开跟踪的情况下在测试环境中重现此功能。
  • 然后我在日志文件上运行一个脚本来查看是否可能发生死锁以及如何发生死锁。我使用 awk 脚本,使用以下算法:
    • 前线
      • 如果获得
        • 将 lockid 添加到该线程的当前锁列表中
        • 将此列表中的每对锁添加到该线程的一组锁对中。例如,对于Lock A -> Lock B -> Lock C生成对的列表(Lock A, Lock B), (Lock A, Lock C), (Lock B, Lock C)
      • 如果释放
        • 从该线程的列表尾部删除当前的 lockid
    • 对于每个锁对,在所有其他线程中搜索反向锁对,每个匹配都是潜在的死锁,因此打印受影响的锁对和线程
    • 我没有让算法变得更聪明,而是检查了锁的获取,看看它是否是真正的死锁。

我在好几天都找不到死锁的原因后才这样做,又花了几天的时间来实施,又花了几个小时才找到死锁。

如果您正在考虑在 Java 中使用这种方法,则需要考虑以下事项:

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