Java 为什么Netbeans会抱怨一个同步调用被一个条件语句包装?

Java 为什么Netbeans会抱怨一个同步调用被一个条件语句包装?,java,netbeans,synchronization,locking,synchronized,Java,Netbeans,Synchronization,Locking,Synchronized,假设我有这样的代码: 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

假设我有这样的代码:

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块内部,那么每个人都必须等待机会来检查t是否为null,而Everyone-1实际上什么也不等待(因为t不会为null)。因此,外部条件

比如说,通过某种奇迹,5个人同时将t==null解析为true。一个用户将获得同步锁,看到t==null仍然为true,并初始化它。然后,该用户将释放锁,下一个用户将锁定它,并几乎立即释放它(因为t!=null),这将继续,直到5个用户通过它为止。一直以来,其他连接的用户都会跳过同步锁,成为made t!中的第一个用户空

那么,为什么Netbeans会抱怨呢?这似乎是最好的办法


想法?

它在抱怨,因为如文所述,它是不安全的——或者至少可能是不安全的

因为
t
不是易变的
volatile
,所以当
东西
仍在构造时,读取器线程可能读取
t
的新值。这将是一个糟糕的举动-使用部分构造的对象是可怕的

在Java5的新内存模型出现之前,它甚至不会是线程安全的,字段标记为
volatile
。新的内存模型在某些情况下是安全的,甚至可能没有
volatile
,但就个人而言,我还是要避免它:

  • 在大多数应用程序中,仅仅在每个调用中进行同步不太可能是一个重大瓶颈
  • 通常,作为静态初始值设定项的一部分进行初始化就足够了:

    private static Thing t = new Thing();
    
  • 对于其他情况,嵌套类还有其他技巧,它们仍然使用静态初始值设定项的惰性,但即使在访问其他成员时,所有这些单一属性也可能是惰性的

  • 对于单行模式,考虑使用枚举代替.< /LI>

有关DCL的旧故障的更多信息,请阅读。(关于JDK 5的当前情况,请参见结尾部分,但请考虑您是否真的希望代码的维护人员考虑所有这些。)

Awesome。这让人困惑(不是你的错),但我想我明白了。就我所知,出于我的目的,我会忽略错误,祈祷不会发生奇怪的事情。@CodyS:为什么,当有更简单更安全的选择时?