3

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

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

我的问题是,乱序是在 java 或其他编程语言中写入数据竞争条件的唯一原因吗?
更新
好的,我对数据竞争进行了更多调查,并从oracle 官方网站上发现了以下内容:

线程分析器检测在多线程进程执行期间发生的数据竞争。在以下情况下会发生数据竞争:

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

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


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

4

1 回答 1

1

我宁愿将数据竞赛定义为

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

事实上,问题的第二个定义用更“官方”的词表达了同样的意思:)

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

现在,对于你的问题:

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

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

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

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

于 2014-11-28T22:30:20.183 回答