一个很好的例子是String的哈希码:
private int hash; // Default to 0public 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)可以读取非null值,而(2)可以读取0。在第一个示例中不会发生这种情况,因为计算是在局部变量和返回值上进行的值也是该局部变量,根据定义,该变量是线程安全的。
编辑2
关于您的提案C4,我认为不可能:
当且仅当所有顺序一致的执行都没有数据争用时,程序才能正确同步。
如果正确同步了程序,则该程序的所有执行将看起来是顺序一致的(第17.4.3节)。
因此,如果程序已正确同步:
- 所有执行似乎顺序一致。
- 所有顺序一致的执行都没有数据争用
因此,我们可以得出结论,所有执行都没有数据争用,因此程序没有数据争用。



