我正在阅读实践中的 Java 并发
我对关于发生前关系的具体解释感到困惑。
它指出,
操作由称为happens-before的偏序排序
“部分排序”到底是什么意思?
(书中有解释,但我不清楚)
偏序意味着不是每对操作都有关系happens-before
。
实际上,并非每对操作都具有这种关系这一事实使您能够同时执行操作。
例如,假设您有操作 A、B、C 和 D。
我们可以定义一个偏序:A must happen before B and C
.
那么 A 和 B 有happens-before
关系,A 和 C 也有。但是,A 和 D 没有这种关系,所以 D 可以在 A 之前、A 之后或在 A 执行时执行。
另一方面,如果happens-before
是一个完整的排序,例如A happens-before B happens-before C happens-before D
(请注意,在这种情况下,对于每一对操作,您都知道哪一个发生在另一个之前,因此它是一个完整的排序),那么操作的执行必须是串行的,并且不可能有并发。
由于您指的是“Java Concurrency in Practice”一书,我想您是关于 Java 内存模型的部分。
对于程序员来说,CPU 执行程序语句的顺序似乎很自然,因为它们在控制流中出现在源代码中。但是优化编译器、CPU 体系结构等几个因素强加了不同的低级行为。然而,这对于执行代码的线程是不可见的。它会表现得好像一切都按顺序发生。
这不再适用于多个线程。当关系存在之前没有发生时,线程可能会观察另一个线程的不同动作顺序。因此,对于这些操作,不存在指定的排序关系。例如当一个线程执行代码时
static Point XY;
…
XY = new Point(3, 4);
另一个线程可能会在该实例的和字段初始化之前观察到Point
实例存储到字段中,从而看到 (0,0) 或 (3,0) 或 (0,4) 点。XY
x
y
XY
因此,动作“赋值”、“赋值x
”和“赋值y
”与读取这些变量之间不存在顺序关系。
如果我们将变量声明更改为 volatile,则在将实例存储到该实例引用和读取该实例引用之间建立起XY
发生前的关系。尽管如此, 和 的写入之间没有顺序,但是现在两个写入都与通过 读取这两个字段具有发生前的关系。Point
XY
x
y
XY
这就是部分排序;有些动作有顺序关系,有些则没有。