Effective Java 第 83 条的示例代码是不是错的?

查看 80|回复 6
作者:Bronya   
关于多线程的,书中给了一个延迟初始化的例子,用的是双重检查方式:
// 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)
        synchronized (this) {
            if (field == null) // Second check (with locking)
                field = result = computeFieldType();
        }
    }
    return result;
}
这里是原书第三版的第 83 条:

这里面的局部变量 result 不是很好理解,而且我在 JDK 21 下跑出来是可能取到 null 的,求大佬解释一下~
破案了,就是错的,看这里https://github.com/jbloch/effective-java-3e-source-code/issues/8,issues 里面给出了解决方法:
private FieldType getField() {
        FieldType result = field;
        if (result == null) { // First check (no locking)
                synchronized (this) {
                        if (field == null) // Second check (with locking)
                                field = result = computeFieldValue();
                        else
                                result = field;
                }
        }
        return result;
}

result, Field, null, fieldtype

beneo   
这个语法我都没见过了
field = result = computeFieldType();
cover   
自问自答?
cover   
就是两个线程一起 synchronized 锁的时候,field 初始化成功了,但是 result 没值,后进 synchronized 那根线程拿到了 null ,修复方案也显而易见,就是让后进的线程也拿到已经被前置线程赋值完成的 field ,其实我觉得最后返回 field 更加方便。
Bronya
OP
  
@cover #2 刚开始没找到那个 ussues ,发完帖子之后又搜索了一下,发现原来真的是作者搞错了,然后赶紧编辑了一下,看起来就像自问自答了😂
flython6   
这个例子确实是错的返回 result
但是我纠结的是为什么要使用局部变量……解释感觉跟没说的一样
flython6   
@cover 哦我懂作者意思了,确实 else 直接返回 field 也可以,还省了一步赋值操作
但是最外面返回 result 主要是想要避免 volatile 变量读取时的缓存行失效,这样可以提升性能(着实是没什么用处的提升)
如果 DCL 最外层检测失败,或者修改后代码没进入 else ,也可以确保最少限度地访问 field (因为每次访问 volitale 都会使缓存行失效从而从主内存加载最新变量副本到工作缓存)
我理解应该是这个意思,欢迎指正
您需要登录后才可以回帖 登录 | 立即注册

返回顶部