当前位置: 首页 > 面试题库 >

正确同步的程序是否仍然允许数据竞争?(第一部分)

燕实
2023-03-14
问题内容

JLS有两个结论:

  • C1:如果一个程序没有数据争用,则该程序的所有执行将看起来是顺序一致的: data-race-free => sequentially consistent
  • C2:如果一个程序正确同步,则该程序的所有执行将看起来是顺序一致的: correctly synchronized => sequentially consistent

如果C1的反事实成立,那么我们可以得出以下结论:

  • C3:如果程序正确同步,则不会出现数据争用: correctly synchronized => data-race-free

但不幸的是,JLS中没有这样的声明,因此我得出了第四个结论:

  • C4:程序可以正确同步并具有数据竞争。

但是,我对这种方法不满意,并且希望获得一个证明该结论是正确的(甚至是错误的),即使是以非正式的方式或示例的方式。

首先,我认为显示包含数据争用的多线程程序的顺序一致执行的代码段有助于理解和解决此问题。

经过认真考虑,我仍然找不到合适的样本。那么,请您给我这样的代码段吗?


问题答案:

一个很好的例子是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)可以读取非null值,而(2)可以读取0。在第一个示例中不会发生这种情况,因为计算是在局部变量和返回值上进行的值也是该局部变量,根据定义,该变量是线程安全的。

编辑2

关于您的提案C4,我认为不可能:

当且仅当所有顺序一致的执行都没有数据争用时,程序才能正确同步。

如果正确同步了程序,则该程序的所有执行将看起来是顺序一致的(第17.4.3节)。

因此,如果程序已正确同步:

  • 所有执行似乎顺序一致。
  • 所有顺序一致的执行都没有数据争用

因此,我们可以得出结论,所有执行都没有数据争用,因此程序没有数据争用。



 类似资料:
  • 方法有一个有趣的属性,它将允许其他线程在被阻止时进入其同步块。例如(假设线程1首先运行): 线程1: 线程2: 线程 2 能够唤醒线程 1 的事实意味着线程 2 进入了同步块,即使其他某个线程位于同一对象的同步块中也是如此。这对我来说很好,但我想知道这是否只发生在或所有会使线程“等待”的方法()上。在我的情况下,我关心,因为如果行为与相同,它会破坏我的代码: 那么,多个线程是否可能因为join调用

  • 在我的环境中,我有JSF 2.2 CDI Spring 4 Wildfly 9 Spring Data在野生服务器中,我配置了两个数据源: 示例(来自工厂) OracleDS(我创建的这个) 在persitence.xml,我有: 我的applicationContext.xml: http://www . spring framework . org/schema/beans/spring-be

  • 问题内容: 我知道在Go中,会将goroutine绑定到一个OS线程,并且不允许其他goroutine在该线程中执行。儿童goroutine也是这样吗? 例如: 这两个goroutine是在单个和排他的OS线程中执行还是仅在第一个线程中执行? 问题答案: 文档的说: LockOSThread 将调用goroutine连接 到其当前的操作系统线程。在调用goroutine退出或调用UnlockOST

  • 问题内容: 据我所知,使用旧的JMM来实现懒惰单调的DCL(双重检查锁定)技巧被打破了,但是我坚信它已被新的JMM和volatile字段所修复… 但是,在这篇不错的文章中,这显然已经足够新,足以引用DCL中的新旧JMM和volatile字段,表明它仍然坏了… 我在这里到那里读到它是固定的,然后我发现了这一点……有人可以最后说它是否损坏了? 我的理解是,通过波动性地在关系发生之前保证发生的先兆并有效

  • 我的一位客户在操作系统级别关闭了TLS 1.0。从那以后,与我们产品的连接就不起作用了。客户没有使用的最新版本。NET 4.6.1。 因为我们没有指定使用的协议,所以我们依赖默认值。根据https://support.microsoft.com/en-us/help/3069494/cannot-connect-to-a-server-by-using-the-servicepointmanage

  • 帮我弄清楚这个.......如何获得使用核心Java概念的带有索引的文件列表?例如,一个文件夹可能包含文件、子文件夹和文件。 ----输出--- 输入路径:e:/gk/demo 文件夹的树表示 %1(主文件夹) \\菜单://// > copy(已提及通过取索引复制文件) 删除(通过取索引删除文件已经提到) 重命名(已提及通过取索引来重命名文件) 退出。 我试过的代码是..重命名索引..是.. 导