竞争条件:从有害到无害

时间:2012-08-30 03:48:40

标签: java concurrency

我从everything2.com

采用以下种族条件的定义
  

竞争条件是运行多个并发进程的情况(出于这些目的,线程也被建模为进程,运行在不同计算机上的进程)将产生不同的结果,具体取决于(未指定,通常不可指定) )操作顺序的细节。

现在考虑以下来自Chapter 3: Race Conditions and Mutual Exclusion的示例:

  

然而,最危险的竞争条件涉及访问共享数据结构。如果   两个线程同时更新相同的数据结构,可能会发生变化   部分由一个线程制成,部分由另一个线程制成。数据结构的内容   然后会变得乱码,这会混淆以后访问它的线程,从而导致   他们崩溃了。

显然,这个样本包含有害的竞争条件。

有一种解决方案可以避免这种有害的竞争条件:

  

诀窍是强制线程一次一个地访问数据结构,所谓的   相互排斥,使每个线程都可以完成更新并离开   结构处于下一个线程的一致状态。

现在根据上面的定义,上述解决方案仍有竞争条件:

  

如果线程A首先进行更改,则共享数据结构的最终内容由线程B填充;如果线程B首先进行更改,则共享数据结构的最终内容由线程A填充。

但现在这是一种无害的竞争条件。

从这个样本中,我得出以下结论:

  

只有在可以避免的情况下,竞争条件才有害。

我不确定上述结论的方向或方向是正确还是不正确。那么有任何样本可以反驳这一结论吗?

3 个答案:

答案 0 :(得分:2)

你是对的。

竞争条件 - 当多个线程访问相同的资源时出现 导致竞争条件的代码部分称为临界区。 请注意,当我们试图避免竞争条件时会发生死锁。

您可以通过创建线程安全代码来避免竞争条件。

  • 本地变量。

    局部变量存储在每个线程自己的堆栈中。这意味着局部变量永远不会在线程之间共享。

  • 本地对象引用。

    所有对象都存储在共享堆中,但如果本地创建的对象永远不会转义它创建的方法,那么它是线程安全的。

  • 将成员字段设置为volatile,final和private。

但是如果你想共享一个变量并仍然以同步的方式控制它的访问。您可以通过以下方式实现这一目标,

  • 使用显式锁(和条件变量)
  • 使用synchronized(隐式锁定)

这仍然不能保证哪个线程首先访问哪个线程以及下一个线程。 对于线程使用信号的这种控制。

可以通过各种方式实现。

  • 通过共享对象发送信号
  • 忙碌等待
  • wait(),notify()和notifyAll()
  • 错过信号
  • 虚假唤醒

答案 1 :(得分:1)

你错过了一个非常重要的观点。对数据结构的任何操作都在几个周期内进行,例如。另外,给出一个非常基本的步骤,

步骤1.检索变量的当前值 步骤2.将所需数字添加到变量的值 步骤3.存储变量

的值

在注册级别,您可以看到更多步骤。但关键是,通过锁定变量/数据结构的访问来避免竞争条件意味着只有一个线程可以读取/写入该数据结构。其他线程不允许读取数据结构,一旦第一个线程完成所有周期,它将允许其他线程进行更改。

线程的第一件事是如果数据结构没有被任何人锁定,则获取Lock。然后它做读/写的东西。

因此,如果正确实施锁定,则不应存在任何竞争条件。

当两个或多个线程可以在相同的数据结构中进行更改时存在竞争条件,如果不通过锁或其他机制来避免它,则可能有害。

答案 2 :(得分:0)

我不同意。当您不想要它时,变化是“有害的”,无论是否可以避免。

显然,当两个进程并行运行时,总是会继续竞争以改变这些数据,因此状态的最终结果可能还取决于竞争。

但是当谈到竞争条件时:当数据的一致性可能被竞赛过程打破时,会发生有害的竞争条件。