在回答正确同步的程序是否仍然允许数据竞争?(第一部分)时,它给了我们一个很好的例子:一个程序的所有执行似乎都是顺序一致的,但它仍然存在数据竞争。它告诉我们为什么JLS中以下结论的另一个方向是不正确的:
如果一个程序没有数据竞争,那么程序的所有执行都将看起来是顺序一致的。
现在看看JLS中的另一个结论:
当且仅当所有顺序一致的执行都没有数据竞争时,程序才能正确同步。
根据这个结论,上面的例子没有正确同步,那么一个正确的程序会不会被错误地同步呢?
在回答正确同步的程序是否仍然允许数据竞争?(第一部分)时,它给了我们一个很好的例子:一个程序的所有执行似乎都是顺序一致的,但它仍然存在数据竞争。它告诉我们为什么JLS中以下结论的另一个方向是不正确的:
如果一个程序没有数据竞争,那么程序的所有执行都将看起来是顺序一致的。
现在看看JLS中的另一个结论:
当且仅当所有顺序一致的执行都没有数据竞争时,程序才能正确同步。
根据这个结论,上面的例子没有正确同步,那么一个正确的程序会不会被错误地同步呢?
您可能需要首先定义什么是正确的程序(不容易)。JCiP 建议(在不同的背景下):
如果一个程序符合它的规范,它就是正确的。
使用该定义,提供的示例是正确的。但是,它没有正确同步(在 上存在数据竞争hash
)。
==> 如该示例所证明的,正确的程序可能会错误地同步。
虽然这似乎没有回答 OP 的问题,但我保留它以供评论。
您可以使用同步集合获得许多竞争条件。例如
Vector<Integer> vector = ...
vector.add(1);
vector.set(0, 1 + vector.get(0));
每个方法都是同步的,但存在竞争条件。这是因为您可以让线程 T1 和 T2 执行。
T1: int tmp1 = vector.get(0);
T2: int tmp2 = vector.get(0);
T1: vector.set(0, 1 + tmp1);
T2: vector.set(0, 1 + tmp2);
在这种情况下 tmp1 == tmp2 这通常不是这种情况。
要正确同步,您将执行以下操作以确保您始终保持锁定。
synchronized(vector) {
vector.set(0, 1 + vector.get(0));
}