如何解决“Double-Checked Locking is Broken"Java中的声明? [英] How to solve the "Double-Checked Locking is Broken" Declaration in Java?

查看:42
本文介绍了如何解决“Double-Checked Locking is Broken"Java中的声明?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在 Java 中为多线程实现延迟初始化.
我有一些这样的代码:

I want to implement lazy initialization for multithreading in Java.
I have some code of the sort:

class Foo {
    private Helper helper = null;
    public Helper getHelper() {
        if (helper == null) {
            Helper h;
            synchronized(this) {
                h = helper;
                if (h == null) 
                    synchronized (this) {
                        h = new Helper();
                    } // release inner synchronization lock
                helper = h;
            } 
        }    
        return helper;
    }
    // other functions and members...
}

而且我收到了双重检查锁定被破坏"的声明.
我该如何解决这个问题?

And I'm getting the the "Double-Checked Locking is Broken" declaration.
How can I solve this?

推荐答案

这里是Item 71: Use lazy Initialization judiciously中推荐的习惯用法有效的 Java:

Here is the idiom recommended in the Item 71: Use lazy initialization judiciously of Effective Java:

如果您需要使用延迟初始化来提高性能实例字段,使用仔细检查成语.这个成语避免了成本访问字段时的锁定初始化后(项目67).这个成语背后的想法是检查该字段的值两次(因此得名仔细检查):一次没有锁定,然后,如果字段似乎未初始化,一个第二次带锁.只有当第二个检查表明该字段未初始化是否调用初始化字段.因为有如果该字段已经存在,则不锁定初始化,关键字段被声明为 volatile(项目66).这是成语:

If you need to use lazy initialization for performance on an instance field, use the double-check idiom. This idiom avoids the cost of locking when accessing the field after it has been initialized (Item 67). The idea behind the idiom is to check the value of the field twice (hence the name double-check): once without locking, and then, if the field appears to be uninitialized, a second time with locking. Only if the second check indicates that the field is uninitialized does the call initialize the field. Because there is no locking if the field is already initialized, it is critical that the field be declared volatile (Item 66). Here is the idiom:

// Double-check idiom for lazy initialization of instance fields
private volatile FieldType field;

private FieldType getField() {
    FieldType result = field;
    if (result != null) // First check (no locking)
        return result;
    synchronized(this) {
        if (field == null) // Second check (with locking)
            field = computeFieldValue();
        return field;
    }
}

这段代码可能看起来有点复杂.尤其是当地需要可变结果可能不清楚.什么这个变量是为了确保字段在公共区域只读取一次已经初始化的情况.虽然不是绝对必要的,但这可能提高性能,更多优雅的标准适用于低级并发编程.在我的机器,上面的方法是关于比显而易见的快 25%没有局部变量的版本.

This code may appear a bit convoluted. In particular, the need for the local variable result may be unclear. What this variable does is to ensure that field is read only once in the common case where it’s already initialized. While not strictly necessary, this may improve performance and is more elegant by the standards applied to low-level concurrent programming. On my machine, the method above is about 25 percent faster than the obvious version without a local variable.

在发布 1.5 之前,仔细检查成语不能可靠地工作,因为volatile 修饰符的语义不够强大,无法支撑它[Pugh01].内存模型介绍在 1.5 版中修复了这个问题[JLS, 17, Goetz06 16].今天,该双重检查习语是一种技术延迟初始化的选择实例字段.虽然你可以申请对静态的双重检查习语领域也是如此,没有理由这样做:惰性初始化持有者类习语是更好的选择.

Prior to release 1.5, the double-check idiom did not work reliably because the semantics of the volatile modifier were not strong enough to support it [Pugh01]. The memory model introduced in release 1.5 fixed this problem [JLS, 17, Goetz06 16]. Today, the double-check idiom is the technique of choice for lazily initializing an instance field. While you can apply the double-check idiom to static fields as well, there is no reason to do so: the lazy initialization holder class idiom is a better choice.

参考

  • Effective Java,第二版
    • 条款 71:明智地使用延迟初始化
    • 这篇关于如何解决“Double-Checked Locking is Broken"Java中的声明?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆