我有一个具有以下配置的PublishSubject:
PublishSubject<Message> messageObserver =
messageObserver
.filter(t -> test(t))
.buffer(eventsSaveTimeSpanInSeconds, TimeUnit.SECONDS, eventsSaveCount)
.subscribe(messages -> saveToDB(messages));
我的应用程序的不同线程正在通过PublishSubject
向此onNext()
写消息。
如我所见,底层buffer
的{{1}}是非线程安全的,因为其onNext如下所示:
ObservableBufferTimed.BufferExactBoundedObserver
为了使比赛情况更加明显,我将public void onNext(T t) {
U b;
synchronized (this) {
b = buffer;
if (b == null) {
return;
}
b.add(t);
if (b.size() < maxSize) {
return;
}
buffer = null;
producerIndex++;
}
if (restartTimerOnMaxSize) {
timer.dispose();
}
fastPathOrderedEmit(b, false, this);
try {
b = ObjectHelper.requireNonNull(bufferSupplier.call(), "The buffer supplied is null");
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
actual.onError(e);
dispose();
return;
}
synchronized (this) {
buffer = b;
consumerIndex++;
}
if (restartTimerOnMaxSize) {
timer = w.schedulePeriodically(this, timespan, timespan, unit);
}
}
和eventsSaveTimeSpanInSeconds
参数设置为1(1秒内发生1个事件)。
问题出现在此块中:
eventsSaveCount
因此,如果两个消息同时在缓冲,则第一个消息将填充synchronized (this) {
b = buffer;
if (b == null) {
return;
}
b.add(t);
if (b.size() < maxSize) {
return;
}
buffer = null;
producerIndex++;
}
并将空值分配给缓冲区变量。新缓冲区将在同步块之后稍后初始化。如果存在竞争条件,则buffer
为null时,由于以下代码,第二条消息将不会被缓冲:
buffer
这是缺陷还是错误的缓冲区行为?如何避免这种情况?
答案 0 :(得分:0)
如果多个线程要调用onNext
,请使用序列化的主题:
Subject<Message> messageObserver = PublishSubject.<Message>create().toSerialized();
messageObserver
.filter(t -> test(t))
.buffer(eventsSaveTimeSpanInSeconds, TimeUnit.SECONDS, eventsSaveCount)
.subscribe(messages -> saveToDB(messages));
// from any thread now
messageObserver.onNext(message);