6

任何人都可以向我解释什么是竞争条件,如何避免它,以及如何在 Java 代码中找到它?

好吧,我几天才知道“比赛条件”,我有两个例子,也许它们不够好,这就是为什么我需要你的帮助:) 希望你们中的任何一个都可以为我解释一下。

示例1:检查然后采取行动:

if(vector.contains(e))//check
{
vector.remove(e)
}

如果有2个线程可以访问,thread1在check vector包含e后挂起,e在vector中,然后thread2访问check,然后从vector中删除e,然后thread1回来做remove动作,会出错,因为e是已被thread2删除。

示例2:读取修改写入:

假设我们在方法中有一个计数器变量,一旦方法被调用,计数器增加 1,

counter++

这不是原子操作,它有 3 个步骤:1. 获取值 2. 增加值 3. 分配给值

我对比赛条件的了解都在这里,希望你能和我分享你的知识:)

谢谢

4

3 回答 3

4

什么是竞态条件?检查这个堆栈溢出问题

竞争条件主要有两种情况:read-modify-write 和 check-then-act。

对于 read-modify-write 经典示例counter++不是原子操作,因此会导致竞争条件。

对于 check-then-act 有多个示例。一个例子是当你在 ConcurrentHashMap 中检查键是否存在,然后在 if-case 中做一些工作。另一个例子是单例类代码:

public Singleton getInstance()
{
   if(_instance == null)
   { 
      _instance = new Singleton();
   }
}

你可以在互联网上阅读更多关于它们的信息。一本关于并发的好书是 Brian Goetz 的 Java Concurrency in Practice。您还可以发现这篇文章很有帮助。

于 2014-12-29T10:15:26.973 回答
3

来自 Java Concurrency in Practice 一书

“当计算的正确性取决于运行时多个线程的相对时间或交错时,就会出现竞争条件;换句话说,获得正确答案时取决于幸运时间”

竞争条件最常见的条件是检查然后行动,其中使用潜在的安全观察来决定下一步做什么。

如果不存在,则另一个常见的竞争条件

对于您的示例 1 。

 if (!vector.contains(element))
   vector.add(element);

尽管 contains 和 add 是原子的,但这种 put-if-absent 操作的尝试具有竞争条件。虽然同步方法可以使单个操作成为原子操作,但需要额外的锁定 - 当多个操作组合成复合操作时。

于 2016-04-12T03:19:58.817 回答
2

答案中提供的示例:“read-modify-write”和“check-then-act”不足以定义竞争条件的情况。

如果您将“竞争条件”理解为由两个或多个线程以不确定的顺序访问共享内存而导致的不可预测结果的条件,其中至少一个访问是用于写入,那么(a)您不需要同时拥有两个“读取”并在同一个线程中“写”。

并且(b)变量的原子定义也不能将我们从潜在的竞争条件中拯救出来。如果一个线程在另一个线程读取原子变量之前或之后写入原子变量并且访问顺序不正确,那么结果仍然是不可预测的。您可以在此处查看对这一点的进一步解释。

于 2015-04-23T01:58:48.390 回答