如何解决“双重锁定被破坏” Java的声明? [英] How to solve the "Double-Checked Locking is Broken" Declaration in Java?

查看:110
本文介绍了如何解决“双重锁定被破坏” 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?

推荐答案

这里是有效的Java

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

项目71:谨慎使用延迟初始化 >

如果您需要在
实例字段上使用延迟初始化来提高性能,请使用重复检查
idiom 。这个习语在初始化之后访问字段
时避免了锁定的成本
(Item
67)。成语背后的想法是
检查字段的值两次
(因此名称​​ double-check ):once
没有锁定,然后,if
字段显示为未初始化,
第二次使用锁定。只有当
第二次检查表明字段
未初始化时,调用
才初始化该字段。因为有
没有锁定,如果该字段已经
初始化,则它是 critical
字段声明 volatile (Item
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;
FieldType getField() {
    FieldType result = field;
    if (result == null) { // First check (no locking)
        synchronized(this) {
            result = field;
            if (result == null) // Second check (with locking)
                field = result = computeFieldValue();
        }
    }
    return result;
}

此代码可能显示有点复杂。
特别的,对本地
变量结果的需要可能不清楚。
这个变量的作用是确保
字段在普通
中只读一次,它已经被初始化了。
虽然不是绝对必要的,但是可以通过应用于
低级并发编程的标准,
提高性能和更多
。在
我的机器,上面的方法约
比没有本地变量的明显的
版本快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,双重检查
idiom没有可靠地工作,因为
volatile修饰符
的语义不够强大,不支持
[Pugh01]。内存模型在版本1.5中引入了
,解决了这个问题
[JLS,17,Goetz06 16]。今天,
double-check idiom是
选项的技术,用于延迟初始化
实例字段。虽然你可以应用
双重检查成语到静态
字段,没有理由
这样做:延迟初始化持有人
类成语是一个更好的选择。

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.



参考




  • 版本


    • 项目71:谨慎使用延迟初始化

    • 这篇关于如何解决“双重锁定被破坏” Java的声明?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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