一个很好的例子可能是 String 的哈希码:
private int hash; // Default to 0
public int hashCode() {
int h = hash;
if (h == 0 && count > 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
这里存在数据竞争,因为哈希可以由不同的线程写入和读取,并且没有发生之前的关系(没有同步)。
但是程序是顺序一致的,因为线程不可能看到不是字符串的实际哈希码的哈希码(当线程执行哈希码方法时,它可以看到 0 并重新计算值,这是确定性的,或者它看到一个有效值)。这是有效的,因为 int 写入是原子的。
编辑
这个(几乎)相同的代码被破坏并且可能返回 0 的哈希码:
public int hashCode() {
if (hash == 0 && count > 0) { //(1)
int h = hash;
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return hash; //(2)
}
因为 (1) 和 (2) 可以重新排序:(1) 可以读取非空值,而 (2) 将读取 0。这在第一个示例中不会发生,因为计算是在局部变量上进行的,并且返回value 也是那个局部变量,根据定义,它是线程安全的。
编辑 2
关于您的提议 C4,我认为这是不可能的:
当且仅当所有顺序一致的执行都没有数据竞争时,程序才能正确同步。
如果程序正确同步,则程序的所有执行都将显示为顺序一致(第 17.4.3 节)。
因此,如果程序正确同步:
- 所有的执行看起来顺序一致。
- 所有顺序一致的执行都没有数据竞争
因此我们可以得出结论,所有执行都没有数据竞争,因此程序没有数据竞争。