如何使用Java检测同步违规问题

9
我想知道有哪些好的方法可以对同步或其他内容进行断言,以便在测试期间检测同步违规情况。例如,在不需要线程安全的类中,我可以使用某种方式来断言,如果其中某个方法被多个线程调用,就会通知我(记录日志或其他方式)。我希望能够实现类似的功能,用于AWT调度线程。
public static void checkDispatchThread() {
    if(!SwingUtilities.isEventDispatchThread()) {
        throw new RuntimeException("GUI change made outside AWT dispatch thread");
    }
}

我只希望有更一般性的东西。问题描述并不是很清晰,但我希望有人能提出一些好的解决方案 =)

9个回答

2

我想你在寻找圣杯。就我所知,这并不存在,并且Java不是一种能够轻易创建这种方法的语言。

《Java并发编程实践》中有一节关于测试线程问题的内容。它特别强调了这样做的难度。


2
当Java中的线程问题出现时,通常与死锁检测有关,不仅仅是监视哪些线程同时访问同步部分。自1.5版以来添加到JRE中的JMX扩展可以帮助您检测这些死锁。实际上,我们在自己的软件中使用JMX自动检测死锁并跟踪其发现位置。

以下是一个示例,介绍如何使用它。


2
IntelliJ IDEA有很多有用的并发检查。例如,当您从同步和非同步上下文同时访问同一对象时,它会警告您;当您在非final对象上进行同步时,它也会提醒您等等。
同样,FindBugs也有许多类似的检查。

有用的并发检查...比如哪些? :) - bvdb

1

除了@Fernando提到的线程死锁之外,多个线程的另一个问题是并发修改及其可能引起的问题。

Java内部做的一件事情是集合类保留了它被更新的次数。然后迭代器在每个.next()上检查该值是否与创建迭代器时的值相同,以查看在迭代期间集合是否已被更新。我认为这个原则可以更普遍地使用。


1

尝试使用ConTestCovertity

这两个工具都会分析代码,找出哪些数据可能在线程之间共享,然后它们会对代码进行插桩(向编译后的类中添加额外的字节码),以检查当两个线程尝试同时更改某些数据时是否会出现问题。然后,这两个线程会一遍又一遍地运行,每次启动它们时稍微调整一下时间偏移量,以获得许多可能的访问模式组合。

此外,请查看这个问题:如何对多线程应用程序进行单元测试?


1
你可能会对Peter Veentjer在博客中提到的一种方法感兴趣,他称之为并发检测器。我不认为他已经开源了这个项目,但是根据他的描述,基本思路是使用AOP来检测你想要进行分析的代码,并记录哪个线程触摸了哪个字段。之后就是手动或自动解析生成的日志的问题。

1

如果您能够确定线程不安全的类,那么静态分析可能会告诉您它们是否“逃逸”以变为对多个线程可见。通常,程序员会在头脑中执行此操作,但显然在这方面他们容易犯错误。工具应该能够使用类似的方法。

话虽如此,从您描述的用例来看,似乎简单记住线程并对其进行断言可能已经足够满足您的需求。

class Foo {

  private final Thread owner = Thread.currentThread();

  void x() {
    assert Thread.currentThread() == owner;
    /* Implement method. */
  }

}

即使禁用了断言,所有者引用仍然存在,因此它并不完全是“免费”的。我也不想在许多类中添加这个样板。

Thread.holdsLock(Object) 方法对您也可能有用。


0

就您提供的具体例子而言,SwingLabs有一些辅助代码来检测事件线程违规和挂起。 https://swinghelper.dev.java.net/

一段时间以前,我使用过JProbe Java性能分析工具。他们的一个工具(Threadalyzer?)查找线程同步违规。看看他们的网页,我没有看到那个名字的工具或者我记得的工具。但是你可能需要仔细看一下。http://www.quest.com/jprobe/performance-home.aspx


-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接