空引用的安全初始化
Safe initialisation of null reference
我想知道初始化为 null 的非最终字段(如果有)存在哪些发布保证。
考虑以下片段:
public class MyClass {
private final CopyOnWriteArrayList<Inner> list = new CopyOnWriteArrayList<>();
//called by thread 1
public void init() {
// initialise Inner instance
list.add(new Inner());
}
//called by thread 2
public void doSomething() {
for (Inner i : list) {
// access non-final field
Object ref = i.ref;
// do something
// ...
// ...
// potentially set i.ref
}
}
private static class Inner {
// initialised by thread 1
Object ref = null;
}
}
假设doSomething()
总是被线程2调用,这样安全吗?线程 2 在第一次访问时会看到什么保证?线程 2 是否有可能看到非空的东西?
JMM 中哪里描述了这种情况的语义?
仅当您使用 具有状态 的有意义的对象初始化字段时,谈论安全发布才有意义。然后,不正确的发布可能导致观察到一个部分构造的对象。
在这种情况下,null
不传达任何状态。它可以被认为是一个不可变的对象。不可变对象没有发布问题。
What guarantees are made about what thread 2 will see the first time it's accessed?
线程 2 在引用 i.ref
时将看到 null
。
请注意,该列表可能为空,因为线程 1 可能尚未向其添加 Inner
。
Is there any possibility thread 2 would see something that's non-null?
没有
JVM
将保证您不会看到 凭空值 ,所以除 null
之外的任何值都不会可能 ,以防 List
不为空(当然在本例中)。如果涉及不同的线程(假设 Thread3
)会更改您的列表(向其添加元素),则 Thread2
可以看到这些更新。请注意 CopyOnWriteArrayList
的各个方法是线程安全的;你的方法 doSomething
不是 。
参见JLS for the specifics or the excellent (and rather complicated, may be just to me) Aleksey article。
我想知道初始化为 null 的非最终字段(如果有)存在哪些发布保证。
考虑以下片段:
public class MyClass {
private final CopyOnWriteArrayList<Inner> list = new CopyOnWriteArrayList<>();
//called by thread 1
public void init() {
// initialise Inner instance
list.add(new Inner());
}
//called by thread 2
public void doSomething() {
for (Inner i : list) {
// access non-final field
Object ref = i.ref;
// do something
// ...
// ...
// potentially set i.ref
}
}
private static class Inner {
// initialised by thread 1
Object ref = null;
}
}
假设doSomething()
总是被线程2调用,这样安全吗?线程 2 在第一次访问时会看到什么保证?线程 2 是否有可能看到非空的东西?
JMM 中哪里描述了这种情况的语义?
仅当您使用 具有状态 的有意义的对象初始化字段时,谈论安全发布才有意义。然后,不正确的发布可能导致观察到一个部分构造的对象。
在这种情况下,null
不传达任何状态。它可以被认为是一个不可变的对象。不可变对象没有发布问题。
What guarantees are made about what thread 2 will see the first time it's accessed?
线程 2 在引用 i.ref
时将看到 null
。
请注意,该列表可能为空,因为线程 1 可能尚未向其添加 Inner
。
Is there any possibility thread 2 would see something that's non-null?
没有
JVM
将保证您不会看到 凭空值 ,所以除 null
之外的任何值都不会可能 ,以防 List
不为空(当然在本例中)。如果涉及不同的线程(假设 Thread3
)会更改您的列表(向其添加元素),则 Thread2
可以看到这些更新。请注意 CopyOnWriteArrayList
的各个方法是线程安全的;你的方法 doSomething
不是 。
参见JLS for the specifics or the excellent (and rather complicated, may be just to me) Aleksey article。