Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 无内存障碍的无序写入:数据竞争的唯一可能原因?_Java_Multithreading_Concurrency_Happens Before - Fatal编程技术网

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

Java 无内存障碍的无序写入:数据竞争的唯一可能原因?,java,multithreading,concurrency,happens-before,Java,Multithreading,Concurrency,Happens Before,在Brian Goetz的Java并发实践中,我遇到了以下几行: 当一个变量被多个线程读取时,就会发生数据争用, 和至少由一个线程写入,但读取和写入不是 排序依据发生在之前。一个正确同步的程序就是其中之一 没有数据竞争;正确同步的程序显示顺序 一致性,意味着程序中的所有操作看起来都是一致的 以固定的全局顺序发生 我的问题是,在java或其他编程语言中,无序写入是造成数据竞争状况的唯一原因吗? 更新 好的,我对数据竞赛做了更多的调查,发现如下所示: 线程分析器检测执行期间发生的数据争用 一个多线程

在Brian Goetz的Java并发实践中,我遇到了以下几行:

当一个变量被多个线程读取时,就会发生数据争用, 和至少由一个线程写入,但读取和写入不是 排序依据发生在之前。一个正确同步的程序就是其中之一 没有数据竞争;正确同步的程序显示顺序 一致性,意味着程序中的所有操作看起来都是一致的 以固定的全局顺序发生

我的问题是,在java或其他编程语言中,无序写入是造成数据竞争状况的唯一原因吗?
更新
好的,我对数据竞赛做了更多的调查,发现如下所示:

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

  • 单个进程中的两个或多个线程同时访问同一内存位置,以及
  • 至少有一个访问用于写入,以及
  • 线程没有使用任何独占锁来控制对该内存的访问
当这三个条件成立时,访问顺序为 非确定性,计算结果可能与 运行到运行取决于该顺序。某些数据竞争可能是良性的(例如 例如,当内存访问用于繁忙等待时),但很多 数据竞争是程序中的错误


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

我宁愿将数据竞争定义为

当读取结果由“内部”(jvm或操作系统控制的)线程调度决定时,从变量写入和读取某个值或引用之间的数据竞争是一种情况

事实上,问题的第二个定义在更“官方”的词语中也是如此:)

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

现在,回答你的问题:

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

在这种特殊情况下,同步保证了在writer线程退出
synchronized
block或method后写入新值之前,您永远无法读取变量的值。如果没有同步,即使在实际发生写操作之后,也有可能读取旧值

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


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

可以。这里的问题是内存可见性。除非您已将变量标记为volatile,或者正在使用synchronized block或lock保护其访问,否则给定线程可能看不到另一个线程所做的更新。@Mac:以原子方式写入该变量是关键。Java支持的原子操作(例如,
Java.util.concurrent.atomic.*
)保证操作是有序的。因此,如果一个线程更新一个原子变量,那么更新将在所有后续读取之前进行。原子操作本身设置了内存屏障。如果您不能以原子方式(或使用同步或锁定)更新变量,那么@BrettOkken的注释中提到的情况可能会发生happen@Mac:这都是关于记忆障碍的。原子操作、可见性、同步和锁都是关于设置内存屏障,以便对特定数据块的操作具有适当的排序语义。我们需要小心谈论原子操作。设置任何基元(double或long除外)都是原子的。这并不意味着它跨线程可见。@jameslarge这两者并不一定冲突。有些数据竞争可能确实是良性的,但程序仍然会被归类为未正确同步。