在开发过程中,可能会遇到生产者生产速度过快,消费者来不及消费的情形。我们就可以用Flowable中的
BackpressureStrategy.BUFFER,其作用会缓存生产者生产的数据,消费者可以会根据负载调用request请求数据,参数是告诉生产者消费者需要的数据量。
看一个例子:
Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(@NotNull FlowableEmitter<Integer> emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
emitter.onNext(4);
emitter.onComplete();
}
}, BackpressureStrategy.BUFFER)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new FlowableSubscriber<Integer>() {
@Override
public void onSubscribe(@NotNull Subscription s) {
new Thread(() -> {
try {
Thread.sleep(1000);
s.request(1); //给我一个数据
Thread.sleep(1000);
s.request(1); //再给我一个数据
Thread.sleep(1000);
s.request(1); //再再给我一个数据
Thread.sleep(1000);
s.request(1);//再再再给我一个数据
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
@Override
public void onNext(Integer integer) {
System.out.println(integer);
}
@Override
public void onError(Throwable throwable) {
System.out.println(throwable.getMessage());
}
@Override
public void onComplete() {
System.out.println("onComplete");
}
});
例子的作用是每1s请求一次数据。 看看源码:
public static <T> Flowable<T> create(FlowableOnSubscribe<T> source, BackpressureStrategy mode) {
...
return RxJavaPlugins.onAssembly(new FlowableCreate<T>(source, mode));
}
FlowableCreate源码中,根据mode适配emitter,这里我们用的是BackpressureStrategy.BUFFER,用的就是BufferAsyncEmitter
public void subscribeActual(Subscriber<? super T> t) {
BaseEmitter<T> emitter;
switch (backpressure) {
case MISSING: {
emitter = new MissingEmitter<T>(t);
break;
}
case ERROR: {
emitter = new ErrorAsyncEmitter<T>(t);
break;
}
case DROP: {
emitter = new DropAsyncEmitter<T>(t);
break;
}
case LATEST: {
emitter = new LatestAsyncEmitter<T>(t);
break;
}
default: {
emitter = new BufferAsyncEmitter<T>(t, bufferSize());
break;
}
}
t.onSubscribe(emitter);
try {
source.subscribe(emitter);
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
emitter.onError(ex);
}
}
在分析BufferAsyncEmitter的源码前,先看看它的父类BaseEmitter,主要分析request方法
BackpressureHelper的作用是加上或者减去我们需要的数据量n,然后调用onRequested方法。
public final void request(long n) {
if (SubscriptionHelper.validate(n)) {
BackpressureHelper.add(this, n);
onRequested();
}
}
好了我们返回BufferAsyncEmitter
生产者生产数据,然后把数据放到队列queue中,然后调用drain方法把队列中的数据出队,这里就会把数据缓存起来。
public void onNext(T t) {
if (done || isCancelled()) {
return;
}
if (t == null) {
onError(new NullPointerException("onNext called with null. Null values are generally not allowed in 2.x operators and sources."));
return;
}
queue.offer(t);
drain();
}
drain方法的作用就是把队列中的数据弹出来发送给消费者,但不是一次性弹出,是根据消费者负载按需弹出的。
void drain() {
if (wip.getAndIncrement() != 0) {
return;
}
int missed = 1;
final Subscriber<? super T> a = downstream;
final SpscLinkedArrayQueue<T> q = queue;
for (;;) {
long r = get(); //获取消费者需要的数据量
long e = 0L; //已经消费的数据量,等到e和r相等时,说明数据已经发给消费者了
while (e != r) {
if (isCancelled()) {
q.clear();
return;
}
boolean d = done;
T o = q.poll();//弹出一个数据
boolean empty = o == null;
//数据发送完毕就可以等着结束了
if (d && empty) {
Throwable ex = error;
if (ex != null) {
error(ex);
} else {
complete();
}
return;
}
if (empty) {
break;
}
a.onNext(o);//交给消费者
e++; //消费数量自增一次,等到和r一样时,说明这次数据消费完毕。
}
if (e == r) {
if (isCancelled()) {
q.clear();
return;
}
boolean d = done;
boolean empty = q.isEmpty();
if (d && empty) {
Throwable ex = error;
if (ex != null) {
error(ex);
} else {
complete();
}
return;
}
}
if (e != 0) {
//减去消费的数据量,等着调用request再次增加消费量
BackpressureHelper.produced(this, e);
}
missed = wip.addAndGet(-missed);
if (missed == 0) {
break;
}
}
}