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

Brian Goetz的实践中通过Java Concurrency时,我遇到了以下行:

当一个变量被多个线程读取并由至少一个线程写入时,会发生数据争用,但读取和写入不是由before-before排序的 。 正确同步的程序是没有数据竞争的程序; 正确同步的程序表现出顺序一致性,这意味着程序中的所有操作似乎都以固定的全局顺序发生。

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

线程分析器检测在执行multithreading进程期间发生的数据争用。 数据竞争发生在:

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

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

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

我宁愿将数据竞争定义为

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

事实上,问题中的第二个定义在更“官方”的单词中表示相同:)

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

现在,问你的问题:

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

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

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

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