在阅读David Karnok关于RxJava内部的this文章时,我遇到了一个实现与RxJava SerializedObserver
类相近的事情的例子。这是代码:
class ValueListEmitterLoop<T> {
List<T> queue;
boolean emitting;
Consumer<? super T> consumer;
public void emit(T value) {
synchronized (this) {
if (emitting) {
List<T> q = queue;
if (q == null) {
q = new ArrayList<>();
queue = q;
}
q.add(value);
return;
}
emitting = true;
}
consumer.accept(value);
for (;;) {
List<T> q;
synchronized (this) {
q = queue;
if (q == null) {
emitting = false;
return;
}
queue = null;
}
q.forEach(consumer);
}
}
}
所以问题是为什么在第一个q
块中引入了内部变量synchronized
?我在第二个synchronized
块中清楚地看到了它背后的原因。是否有任何原因导致我不能使用:
if (queue == null) {
queue = new ArrayList<>();
}
queue.add(value);
答案 0 :(得分:2)
我觉得将字段读入局部变量是一个好习惯,特别是如果它们被多次使用并且附近有一些易失/同步访问。
例如,以下是一种常见模式:
volatile boolean cancelled;
final Queue<T> queue;
final Subscriber<? super T> actual;
void drain() {
Subscriber<? super T> a = actual;
Queue<T> q = queue;
for (;;) {
if (cancelled) {
return;
}
T v = q.poll();
if (v == null) {
a.onComplete();
return;
}
a.onNext(v);
}
}
如果a
和q
是字段访问,则处理器/ JVM必须始终从内存中读取它们,因为cancelled
和内部类似的原子的易失性访问poll()
。