【问题标题】:Function has different behaviors in simultaneously calls under stress testing在压力测试下,函数在同时调用中具有不同的行为
【发布时间】:2018-04-19 14:33:10
【问题描述】:

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

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

public void doPayment(Acccount account) throws MyException {

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

如果此函数同时调用两次,当账户有钱只用于一次付款时,就会进行两次付款。

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

【问题讨论】:

  • 了解 Java 中的并发和同步。
  • 快速而肮脏的解决方案是在方法签名中添加synchronized 关键字。但是,是的,并发应该是任何半认真的 Java 程序员的基本知识

标签: java multithreading load-testing stress-testing


【解决方案1】:

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

public synchronized void doPayment(Acccount account) throws MyException {

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

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

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

您应该研究并发性和同步性,以确保您做对了。众所周知,并发问题很难追踪。

【讨论】:

    【解决方案2】:

    使用同步

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

    【讨论】:

    • 无论key 应该是什么,似乎没有必要,您可以在this 上同步。如果将整个方法体包装在 synchronized 中,则可以改为同步整个方法
    • @Turing85 但我认为同步方法不是一个好习惯
    • @Turing85 你在this 上同步,然后你最终会得到两个不相关的方法在多线程上下文中相互阻塞。不好的建议。
    • key 理想情况下应该是我的回答中描述的帐户对象。我同意解决方案。只是他没有提到 key 应该是 account 对象
    • @akshayapandey Key 不是 Account 对象,它只是一个对象。请查看并发和密钥
    【解决方案3】:

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

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

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

    最好的问候。

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-07-28
        • 1970-01-01
        • 2016-08-13
        • 1970-01-01
        • 2013-06-25
        • 1970-01-01
        • 2019-07-14
        • 2015-10-29
        相关资源
        最近更新 更多