你注意到 Java 多线程并发示例中的 Race Condition 了吗? 如何处理?

已发表: 2019-12-11

你有没有注意到-java-multi-threading-concurrency-example中的竞争条件

前段时间我写了一篇关于生产者消费者示例以及如何在 Java 中更好地处理读/写操作的文章。 同样,在本教程中,我们将讨论Race ConditionThread locking

如果您有以下任何问题,那么您来对地方了:

  • Java 竞争条件示例
  • 互斥量 java 示例
  • 多线程——什么是竞争条件?
  • 比赛条件和关键部分
  • 什么是比赛条件?
  • 如何通过示例处理 Java 中的竞争条件

为什么会出现 Java 中的竞争条件?

Java 中的竞态条件发生在two or more threads尝试修改/更新共享数据same time

让我们看一下下面的程序逻辑:

这是一个非常简单的银行示例,您将在其中depositwithdraw 100 times 。 您将总共存入 $100 100 次 = $100 x 100 = $10,000 并且您将总共提取 $50 100 次 = $50 x 100 = $5,000。 计划完成时,您的银行中应该有 5000 美元。

以下是步骤:

  1. 创建类 CrunchifyRaceCondition.java
  2. 创建类 CrunchifyTransaction.java
  3. 创建类 CrunchifyBankAccount.java
  4. 我们将运行 CrunchifyRaceCondition 类,它将启动存款和取款循环 100 次。
  5. 我们将with Synchronized block运行它以检查结果
  6. 我们将在without Synchronized block的情况下运行它来检查结果

CrunchifyRaceCondition.java

CrunchifyTransaction.java

CrunchifyBankAccount.java

请检查上面的第 24 和 34 行。 保留Synchronized关键字并运行您的程序。 您应该看到正确的结果,如下图所示。

Java 同步块关键字 - Crunchify

现在从第 24 行和第 34 行删除同步关键字并运行相同的程序。

您可能需要多次运行此程序才能看到问题。 在 java 中,不能保证你会一直看到 Race 条件。

没有同步块关键字的 Java - Crunchify

如果您有企业级应用程序并且您正在谈论每秒数百万笔交易,那么竞争条件可能会给您的公司带来灾难。

现在的问题是如何避免 Java 应用程序中的竞争条件?

  1. 如果竞态条件是对某些共享内存数据结构的更新,则需要以适当的方式同步对数据结构的访问和更新。
  2. 如果竞争条件是更新数据库,则需要重组 SQL 以使用适当粒度级别的事务。
  3. 在投入生产之前进行负载测试并不是一个坏主意。 更多的负载可能会导致罕见的竞争条件。 最好先修复它,然后再修复它。
  4. 确保没有要写入的全局变量。
  5. 在 Java 中,每个对象都有一个且只有一个与之关联的监视器和互斥锁。 然而,单个监视器有几个门,每个都由synchronized关键字指示。 当一个线程通过synchronized关键字时,它有效地锁定了所有的门。
  6. 当然,如果一个线程没有通过synchronized关键字,它还没有锁门,其他线程随时可以自由插入。