【问题标题】:Java Concurrency: What leads to the insecurity in object publication?Java 并发:是什么导致了对象发布的不安全性?
【发布时间】:2020-08-30 16:44:53
【问题描述】:

考虑以下代码:

public class Resource {
    public int val;
    public Resource() {
        val = 3;
    }
}

public class UnsafePublication {
    public static Resource resource;

    public static void initialize() {
        resource = new Resource();
    }
}

在线程1中

UnsafePublication.initialize();

在线程2中

while (true) {
    if (UnsafePublication.resource != null) {
        System.out.println(UnsafePublication.resource.val);
        break;
    }
}

我们知道不安全的发布可能导致 Thread2 打印 0 而不是 3。

查阅了很多参考资料,总结出两种解释:

  1. 假设赋值resource = new Resource();确实写透了,所以Thread2 会发现UnsafePublication.resource 不为空。但是Resource的构造函数中的赋值val = 3;没有写透,所以val会是默认的0值。
  2. new Resource() 分配给resource 时会重新排序。具体来说:

    1. 为资源对象分配内存
    2. 调用 Resource 的构造函数来初始化对象
    3. 将对象分配给“资源”字段

    被重新排序为:

    1. 为资源对象分配内存
    2. 将对象分配给“资源”字段
    3. 调用 Resource 的构造函数来初始化对象。

    所以如果 Thread1 在重新排序的版本中刚刚完成了 step2,并且 Thread2 被换入,那么 Thread2 会发现 UnsafePublication.resource.val 是默认的 0 值。

所以这是我的问题:这两种解释都正确且可能吗?而在现实世界中,这两个因素是否甚至可能混合在一起使情况变得更加复杂?

【问题讨论】:

  • 它不会打印0as resourcewould be null
  • @jhamon 是的!由于resource 不是易失性的,因此不保证Thread1 中的更新对Thread2 可见,但有可能。 (如果我没有以错误的方式理解一些参考资料......)在解释1中,我假设resource 确实是写透并且对其他线程可见。
  • 您的示例代码中没有线程,因此它的行为与您声称的不同。
  • @user207421 在代码块的底部,我comet了两个线程的动作......

标签: java concurrency


【解决方案1】:

这里有三种可能。

  • Thread2 可以将资源视为null
  • Thread2 可能会查看对部分构造实例的引用(即在堆上分配内存,但变量尚未初始化),因此 val 变量的值可能为零。
  • Thread2 可能会观察到一个完全构造的实例和变量的最新值,即 3。

事实上,您无法预测程序的行为,因为在写入和后续读取操作之间建立链接之前没有任何事情发生。所以,所有的事件组合都是可能的。

【讨论】:

  • 谢谢! 部分构造是指我在解释2中谈到的情况吗?那么解释1呢?实例会在 Thread1 中完全构建,但其中的 val 对 Thread2 仍然不可见吗?
  • 两种解释相吻合。
  • 我不确定,但在resource = new Resource(); 上,构造函数不需要在分配“资源”之前完全执行吗?从而使第二点不可能?
  • @jhamon 实际上resource = new Resource() 语句包含三个步骤。首先,在堆上为对象分配内存。这就是创造。其次,调用该对象的构造函数。这是初始化。第三,将对象的地址分配给resource。第二步和第三步可以互换优化,我发现here
  • 有趣。我找到了一个相关的帖子here
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多