1

此代码用于演示双重检查锁定反模式:

@NotThreadSafe
public class DoubleCheckedLocking {
    private static Resource resource;

    public static Resource getInstance() {
        if (resource == null) {
            synchronized (DoubleCheckedLocking.class) {
                if (resource == null)
                    resource = new Resource();
            }
        }
        return resource;
    }
}

我可以通过修改它来避免这个问题:

@NotThreadSafe
public class DoubleCheckedLocking {
    private static Resource resource;

    public static Resource getInstance() {
        if (resource == null) {
            synchronized (DoubleCheckedLocking.class) {
                if (resource == null){
                    Resource r=new Resource();
                    resource = r;
                }
            }
        }
        return resource;
    }
}

据我所知,

Resource r=new Resource();
resource = r;

该编译器应该为此提供发生之前的关系。

4

3 回答 3

4

据我所知,唯一已知的双重检查锁定模式的实现(适用于 JDK5 及更高版本)使用了 'volatile' 关键字。请参阅使用 Volatile 修复双重检查锁定

于 2012-09-15T15:54:40.290 回答
2
public static Resource getInstance() {
    if (resource == null) {
        synchronized (DoubleCheckedLocking.class) {
            if (resource == null){
                Resource r=new Resource();
                resource = r;
            }
        }
    }
    return resource;
}

唯一能保证线程之间正确可见性的方法是通过同步(通过、...)创建同步关系。synchronizedvolatile

如果您没有同步关系,则不需要一个线程来查看来自其他线程的修改。

在这种情况下,线程可以创建 aResource并将对它的引用存储在resource. 然后第二个线程可能会进入getInstance(),并查看resource != null。第二个线程不能保证看到resource's 构造的所有效果,因为它不与第一个线程同步。

于 2012-09-15T16:35:51.340 回答
2

允许编译器优化:

Resource r=new Resource();
resource = r;

resource=new Resource();

所以你的调整是无效的。

于 2012-09-15T18:35:54.700 回答