java - 使用 findbugs 或其他分析工具检测竞争条件

标签 java thread-safety findbugs

下面的 bean 不是线程安全的:方法 addIfNotExist 不是同步的,因此可能由于竞争条件而将相同的术语添加两次。我使用 JCIP 注释 @ThreadSafe 对该类进行了注释,希望 FindBugs 会发现该实现不是线程安全的并将其标记为错误,但事实并非如此。是否有任何工具可以识别代码库中的这些类型的错误?

addIfNotExist 和 isExist 方法应该同步以使该 bean 线程安全。 isExist 方法是否也应该同步?

package com.test;

import java.util.ArrayList;

import java.util.Collection;

import net.jcip.annotations.GuardedBy;

import net.jcip.annotations.ThreadSafe;

@ThreadSafe

public class Dictionary {

    @GuardedBy("this")
    public Collection<String> terms = new ArrayList<String>();

    public void addIfNotExist(final String input) {
        if (!this.terms.contains(input)) {
            this.terms.add(input);
        }
    }

    public boolean isExist(final String input){
        return this.terms.contains(input);
    }

    public void remove(final String input){
        this.terms.remove(input);
    }
}

最佳答案

非常好difficult编写具有任何复杂程度的安全多线程代码:这种类型的锁定(使用监视器)充满了各种间歇性竞争条件、死锁和活锁问题,这些问题经常逃避检测,直到推广到生产系统;如果可以,请考虑使用 message passing , software transactional memorypersistent data structures相反。

FindBugs(或者实际上任何静态分析工具)在检测非线程安全代码方面只能走这么远:根据它们的定义,竞争条件是时间敏感的——它们需要多次执行运行才能显现,所以静态分析在这方面是因为他们不运行任何代码,只寻找通用代码签名。恕我直言,检测问题的最佳方法是:

  • 第二双眼睛 - 与熟悉代码的同行进行严格的代码审查 - 一起寻找原始作者不会立即发现的错误。

  • 持续集成和详尽的自动化测试,在各种硬件上执行多线程,并无情地调查任何“间歇性”测试失败。

在回答第二个问题时,是的,所有引用terms 的方法都应该由同步监视器保护,无论是写操作还是读操作;考虑如果线程 A 调用 remove("BOB") 而线程 B 正在调用 isExists("BOB") 时会发生什么,而您没有同步 - 线程 A 将是压缩数组列表,而线程 B 将尝试遍历它。

充其量,您将无法确定 isExists("BOB") 的结果,但 B 完全有可能间歇性地抛出 IndexOutOfBounds 异常,因为数组的大小在遍历时可能会发生变化(即缩小)。

同步,虽然你仍然不能确定调用的顺序(由于调度的不确定性),但至少你可以保证操作在条款 将是原子的——也就是说,在当前线程运行时它们不会被其他东西改变。

关于java - 使用 findbugs 或其他分析工具检测竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5571657/

相关文章:

java - 连接两个类

java - 具有单值的 JPA OR 条件

Java - 不实例化对象时是否需要 static 和 volatile?

java - FindBugs插件Eclipse发现的错误

java - 奇怪的 Findbugs 错误与 equals

java - 什么时候使用静态属性?

java - 比较 Scala 列表和 Java 列表

java - map 的线程安全性,在应用程序范围的 bean 中私下使用,并且仅在构建后用于准备目的

python - 当两个异步任务访问同一个可等待对象时是否安全?

java - Findbug 不可变日期修复不起作用