gpt4 book ai didi

java - 为什么 Netbeans 提示同步调用被条件包裹?

转载 作者:行者123 更新时间:2023-11-30 06:33:01 26 4
gpt4 key购买 nike

假设我有这样的代码:

private static Thing t = null;
private static final Object lock = new Object();

public static void foo() {
if(t == null) { //Netbeans warning on this line.
synchronized(lock) {
if(t == null) {
t = new Thing();
}
}
}
...Do stuff with t...
}

现在,foo 托管在服务器上,并且可能会被许多用户同时调用。函数 foo 的目的是初始化 t,如果它还没有,否则,使用初始化的实例来做任何需要做的事情。

但是,Netbeans 对这样的代码发出警告:

移除外部条件语句

带有工具提示:

双重检查锁定

双重检查锁定的要点是避免等待人们释放锁的瓶颈。如果唯一检查 t 是否为 null 的检查是在同步块(synchronized block)内部,那么每个人都必须等待他们的机会来查看 t 是否为 null,并且每个人-1 实际上什么都不等待(因为 t 不会为 null) .因此外部条件。

有了它,比如说,奇迹般地,5 个人同时将 t == null 解析为 true。一个用户将获得同步锁,看到 t == null 仍然为真,并对其​​进行初始化。然后,该用户将释放锁,下一个用户将锁定它,并几乎立即释放它(不再是 t != null),这将一直持续到 5 个用户通过它。一直以来,其他连接的用户跳过同步锁,因为第一个用户使 t != null。

那么,为什么 Netbeans 会提示呢?据我所知,这似乎是最好的方法。

想法?

最佳答案

它提示是因为正如所写的那样,它是不安全的 - 或者至少可能是。

因为 t 不是 volatile,读取器线程可能会读取 t 的新值 Thing 仍在构建中。那将是一个糟糕的举动 - 使用部分构造的对象是可怕的。

在 Java 5 的新内存模型之前,如果字段标记为 volatile,它甚至都不是线程安全的。使用在某些情况下安全的新内存模型,甚至可能没有 volatile,但我个人还是会避免使用它:

  • 在大多数应用程序中,仅在每次调用中同步不太可能成为显着瓶颈
  • 通常作为静态初始化程序的一部分进行初始化就足够了:

    private static Thing t = new Thing();
  • 对于其他情况,嵌套类有替代技巧,它们仍然使用静态初始化器的惰性,但即使访问其他成员时所有这个单一属性也是惰性的。

  • 对于直接单例模式,请考虑改用枚举。

有关 很多 的有关 DCL 旧故障的更多信息,请阅读 The "Double-Checked Locking is Broken" Declaration . (请参阅结尾部分了解 JDK 5 的当前情况 - 但想想您是否真的希望代码的维护者考虑所有这些。)

关于java - 为什么 Netbeans 提示同步调用被条件包裹?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8437593/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com