没有内存屏障的乱序写入:数据竞争的唯一可能原因?

时间:2014-07-05 23:18:06

标签: java multithreading concurrency happens-before

在Brian Goetz 的实践中经历 Java Concurrency时,我遇到了以下一行:

  

当多个线程读取变量时发生数据争用,   并且由至少一个线程编写,但读写不是   按发生前订购。正确同步的程序就是其中之一   没有数据竞赛;正确同步的程序显示顺序   一致性,意味着程序中的所有操作都显示出来   发生在一个固定的全球秩序中。

我的问题是,乱序是写java或其他编程语言中数据竞争条件的唯一原因吗?
更新
好的,我做了一些关于数据竞争的调查,并从oracle official site找到了以下内容:

  

线程分析器检测执行期间发生的数据争用   一个多线程的过程。数据竞争发生在:

     
      
  • 单个进程中的两个或多个线程同时访问同一内存位置,
  •   
  • 至少有一个访问用于写入,
  •   
  • 线程没有使用任何独占锁来控制它们对该内存的访问。
  •   
     

当这三个条件成立时,访问顺序为   非确定性的,并且计算可能会给出不同的结果   运行以根据该顺序运行。一些数据争夺可能是良性的(因为   例如,当内存访问用于忙等待时,但很多   数据竞争是程序中的错误。


在本部分中,提到:访问顺序是非确定性的
它是在讨论线程访问内存位置的顺序吗?如果是,那么同步永远不会保证线程将访问代码块的顺序。那么,同步如何解决数据竞争问题呢?

1 个答案:

答案 0 :(得分:1)

我宁愿将数据竞赛定义为

  

从变量写入和读取某些值或引用之间的数据竞争是当读取结果由"内部" (jvm或os控制)线程调度。

事实上,问题的第二个定义在更多"官方"单词:)

换句话说,考虑线程A向变量写入一些值,而线程B尝试读取它。如果您错过任何类型的同步(或其他可以在写入和后续读取之间提供发生 - 保证之前)的机制,则程序在线程A和B之间会有数据争用。

现在,问你的问题:

  

是否在讨论线程访问内存位置的顺序?如果是,那么同步永远不会保证线程将访问代码块的顺序。

在该特定情况下的同步保证在写入器线程退出synchronized块或方法之后,在编写器线程写入新值之前,您将永远无法读取该变量的值。如果没有同步,即使实际发生了写操作,也有可能读取旧值。

关于访问顺序:通过以下方式确定同步:

让我们再看看我们的主题A和B.操作顺序现在是顺序的 - 在线程A完成写入之前,线程B将无法开始读取。为了清楚地说明这种情况,想象一下写作和阅读真的是一个漫长的过程。如果没有同步,这些操作将能够相互交错,这可能会导致读取一些无意义的值。