在Brian Goetz 的实践中经历 Java Concurrency时,我遇到了以下一行:
当多个线程读取变量时发生数据争用, 并且由至少一个线程编写,但读写不是 按发生前订购。正确同步的程序就是其中之一 没有数据竞赛;正确同步的程序显示顺序 一致性,意味着程序中的所有操作都显示出来 发生在一个固定的全球秩序中。
我的问题是,乱序是写java或其他编程语言中数据竞争条件的唯一原因吗?
的更新
好的,我做了一些关于数据竞争的调查,并从oracle official site找到了以下内容:
线程分析器检测执行期间发生的数据争用 一个多线程的过程。数据竞争发生在:
- 单个进程中的两个或多个线程同时访问同一内存位置,
- 至少有一个访问用于写入,
- 线程没有使用任何独占锁来控制它们对该内存的访问。
当这三个条件成立时,访问顺序为 非确定性的,并且计算可能会给出不同的结果 运行以根据该顺序运行。一些数据争夺可能是良性的(因为 例如,当内存访问用于忙等待时,但很多 数据竞争是程序中的错误。
在本部分中,提到:访问顺序是非确定性的
它是在讨论线程访问内存位置的顺序吗?如果是,那么同步永远不会保证线程将访问代码块的顺序。那么,同步如何解决数据竞争问题呢?
答案 0 :(得分:1)
我宁愿将数据竞赛定义为
从变量写入和读取某些值或引用之间的数据竞争是当读取结果由"内部" (jvm或os控制)线程调度。
事实上,问题的第二个定义在更多"官方"单词:)
换句话说,考虑线程A向变量写入一些值,而线程B尝试读取它。如果您错过任何类型的同步(或其他可以在写入和后续读取之间提供发生 - 保证之前)的机制,则程序在线程A和B之间会有数据争用。
现在,问你的问题:
是否在讨论线程访问内存位置的顺序?如果是,那么同步永远不会保证线程将访问代码块的顺序。
在该特定情况下的同步保证在写入器线程退出synchronized
块或方法之后,在编写器线程写入新值之前,您将永远无法读取该变量的值。如果没有同步,即使实际发生了写操作,也有可能读取旧值。
关于访问顺序:通过以下方式确定同步:
让我们再看看我们的主题A和B.操作顺序现在是顺序的 - 在线程A完成写入之前,线程B将无法开始读取。为了清楚地说明这种情况,想象一下写作和阅读真的是一个漫长的过程。如果没有同步,这些操作将能够相互交错,这可能会导致读取一些无意义的值。