函数在压力测试下同时调用有不同的行为

Function has different behaviors in simultaneously calls under stress testing

我在一个软件中发现了一个只有在压力测试下才会出现的错误。如果同时或几乎同时调用,则函数被大量调用并且具有不同的行为。

我编了一个例子来说明正在发生的事情:

public void doPayment(Acccount account) throws MyException {

    if (isMoneyAvailable(account)) {
        confirmPayment(account);
    }else{
        throw new MyException(myErrorCode);
    }
}

如果同时调用该函数两次,当账户有钱支付一次时,即完成两次支付。

你有什么办法可以防止这种错误吗?

您最简单的解决方案可能是同步它:

public synchronized void doPayment(Acccount account) throws MyException {

    if (isMoneyAvailable(account)) {
        confirmPayment(account);
    } else {
        throw new MyException(myErrorCode);
    }
}

这将确保任何时候只有一个线程可以使用此对象中的此方法。

这可能不是您想要的。例如,如果您有多个包含此方法的对象(可能在超类中),那么您应该使用不同的机制。

您应该学习并发和同步以确保您掌握了正确的知识。众所周知,并发问题很难追踪。

使用同步

public void doPayment(Acccount account) throws MyException {
    synchronized(key){
    if (isMoneyAvailable(account)) {
        confirmPayment(account);
    }else{
        throw new MyException(myErrorCode);
    }
}
}

我不是多线程计算方面的专家,但您必须考虑到您建议的此调用存在并发性。 基本上我认为你可以简单地这样做:

public synchronized void doPayment(Acccount account) throws MyException {

    if (isMoneyAvailable(account)) {
        confirmPayment(account);
    }else{
        throw new MyException(myErrorCode);
    }
}

在不知道包含此方法的 class 的任何其他内容的情况下,这是我的最佳答案。不同之处在于关键字 "syncronized" 允许 java 将 "doPayment" 调用作为原子操作,因此没有人可以干涉。 有关同步的更好解释,请查看 java reference about it.

此致。

您可以只在帐户对象上同步,而不是在整个方法上同步。这样它会表现得更好。这本质上是因为我们不希望多个线程同时访问帐户对象。只要他们正在访问不同的帐户对象,他们就不应该互相阻止。

public void doPayment(Acccount account) throws MyException {
    synchronized(account){
    if (isMoneyAvailable(account)) {
        confirmPayment(account);
    }else{
        throw new MyException(myErrorCode);
    }
}
}