RxJava2 源码分析(五)

目的

分析Flowable的相关源码,了解一下背压的知识。

从例子开始

demo

        Flowable
                .create<Int>({
                    it.onNext(1)
                    it.onNext(2)
                    it.onComplete()
                }, BackpressureStrategy.BUFFER)
                .subscribe {
                    System.out.println(it)
                }

看看 create 方法创建了一个什么对象:

Flowable

io.reactivex.Flowable#create

    public static <T> Flowable<T> create(FlowableOnSubscribe<T> source, BackpressureStrategy mode) {
        ObjectHelper.requireNonNull(source, "source is null");
        ObjectHelper.requireNonNull(mode, "mode is null");
        return RxJavaPlugins.onAssembly(new FlowableCreate<T>(source, mode));
    }

创建了一个 FlowableCreate 对象,由于 Flowable 与 Observerable 差不多,所以下面我们按照分析 Observerable 的思路来分析 Flowable。

FlowableCreate

类结构

public final class FlowableCreate<T> extends Flowable<T> {...}

这个没啥说的,与 Observerable 一样。

构造函数

    public FlowableCreate(FlowableOnSubscribe<T> source, BackpressureStrategy backpressure) {
        this.source = source;
        this.backpressure = backpressure;
    }

也与 Observerable 差不多,就是两套代码吧。一个以 Observerable 开头,一个以 Flowable 开头,嗯,现在我对源码的探究就只到了这个程度,可能还有别的不同,暂时还未发现。

subscribeActual 方法

demo 中 backpressure 我们传递的是 BackpressureStrategy.BUFFER,所以 emitter 的值是 BufferAsyncEmitter。

    @Override
    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 这个类就好了。

FlowableCreate.BufferAsyncEmitter

类结构

这个类是 FlowableCreate 的内部类,可以想到其他的 Emitter 应该也是内部类

继承了 BaseEmitter

    static final class BufferAsyncEmitter<T> extends BaseEmitter<T> {...}
FlowableCreate.BaseEmitter

类结构

注意这个类继承至 AtomicLong

    abstract static class BaseEmitter<T>
    extends AtomicLong
    implements FlowableEmitter<T>, Subscription {...}

这个类实现了一些通用的方法,比如 onError,onComplete,cancel等等。

其中只有一个方法需要看看:

BaseEmitter#request

        @Override
        public final void request(long n) {
            // 判断 n 是不是正数
            if (SubscriptionHelper.validate(n)) {
                // 是正数,将 n 设置给自己
                // 上面有说,这个类继承了 AtomicLong,所以它可以持有一个 Long 型的引用
                BackpressureHelper.add(this, n);
                // 钩子方法
                onRequested();
            }
        }

好了,到这里 BaseEmitter 的方法就分析的差不多了,这个类只是提供了一些默认的实现方法,没有别的逻辑,把它当成一个普通的父类就好了。

FlowableCreate.BufferAsyncEmitter

再回到 BufferAsyncEmitter 里面,看构造函数

构造函数

        BufferAsyncEmitter(Subscriber<? super T> actual, int capacityHint) {
            super(actual);
            // 这里有一个新类
            this.queue = new SpscLinkedArrayQueue<T>(capacityHint);
            this.wip = new AtomicInteger();
        }

SpscLinkedArrayQueue 这个类不展开介绍了,贴一段注释就明白了。

A single-producer single-consumer array-backed queue which can allocate new arrays in case the consumer is slowerthan the producer.

一个单生产者单消费者数组支持的队列,它可以在消费者比生产者慢的情况下分配新的数组(自动增长)。

机翻都能看的懂吧,源码就是实现了这样功能的队列,有兴趣的可以看看。

我们把 SpscLinkedArrayQueue 当成一个队列就好。注意这里的初始容量是 128,但是会自动增长。

看完构造方法,再看 onNext 方法。

onNext

        @Override
        public void onNext(T t) {
            // isCancelled 是父类的方法
            // 当我们调用 setDisposable 方法的时候,父类就会保存这个 Disposable 的引用到 serial 字段
            // 如果该 Disposable 调用了 dispose 方法,那么 isCancelled 会返回 true
            // 调用父类的 cancel 方法,isCancelled 也会返回 true(内部调用了 serial.dispose())
            // 数据发送完毕或者发生错误,isCancelled 也会返回 true(内部调用了 serial.dispose())
            // done 只有数据发生完毕或者发生错误才会为true
            if (done || isCancelled()) {
                return;
            }

            // 不允许发送的数据为null
            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();
        }

看来,onNext 的主要目的,就是先将数据加入到队列里面,然后调用 drain 方法。继续看 drain 方法。

drain

这个方法有点长,变量名也有点蛋疼,但是慢慢分析,不难

在阅读源码的时候,一定要有耐心。阅读源码的过程其实是一个提升自己理解力的过程。

既然你需要阅读别人的源代码,那么你的理解力肯定是处于弱势的,不然的话,你一看就懂,那就说明源码的东西在作者写出来之前你都已经掌握了,那么阅读源码对自己没有任何好处。

所以,阅读源码的过程,就是需要慢慢提升自己的理解力,来达到与作者的理解力一样的程度。

        void drain() {
            // wip 这个变量到后面分析,因为涉及到别的方法,单看这一个方法看不出什么东西来
            if (wip.getAndIncrement() != 0) {
                return;
            }

            int missed = 1;
            // 这两个变量名有点吊
            final Subscriber<? super T> a = actual;
            final SpscLinkedArrayQueue<T> q = queue;

            for (;;) {
                // 这里,获取设置的引用值,因为这个类是继承的 AtomicLong
                // 前面我们分析过,只有 request 方法才会设置引用值
                // 至于哪里调用了 request 方法,我们后面分析
                // 这里将这个值当作 Long.MAX_VALUE
                long r = get();
                long e = 0L;

                // 进入循环
                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 方法,会调用 onError
                            error(ex);
                        } else {
                            // 调用父类 complete 方法,会调用 onComplete
                            complete();
                        }
                        return;
                    }

                    // 队列为空,则跳出循环
                    if (empty) {
                        break;
                    }

                    // 调用 onNext 方法,o 是从队列取出来的数据
                    a.onNext(o);

                    // e 的值累加
                    e++;
                }

                // 这里要判断一下 e 与 r 是否相等,
                // 因为如果队列为空的话,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) {
                    // 因为发送了 e 个数据,所以将引用值更新
                    // 内部就是将引用自减少了 e
                    BackpressureHelper.produced(this, e);
                }

                // 这个后面分析
                missed = wip.addAndGet(-missed);
                if (missed == 0) {
                    break;
                }
            }
        }

drain 的主要作用,就是当我们调用 request(num) 请求 num 个数据的时候,这个方法会从队列中取出 num 个数据出来给我们。

可以思考一下,如果我们没有调用,request 方法,会怎么样?

drain

简化后的代码

        void drain() {

            ...
            for (;;) {
                long r = get();
                long e = 0L;

                // 没有调用 request,导致 r 为 0,这里进不去
                while (e != r) {
                    ...
                }

                // 相等
                if (e == r) {
                    // 没有取消
                    if (isCancelled()) {
                        ...
                    }

                    boolean d = done;

                    // 队列不为空
                    boolean empty = q.isEmpty();

                    // 进不去
                    if (d && empty) {
                        ...
                    }
                }

                // 进不去
                if (e != 0) {
                    ...
                }

                missed = wip.addAndGet(-missed);
                // 满足,跳出循环
                if (missed == 0) {
                    break;
                }
            }
        }

可以看到,如果我们没有调用 request 方法,虽然 onNext 方法被调用了,将数据加入到了队列中,但是却无法从队列中取出数据,即下游的观察者收不到任何数据。

还有两个遗留的问题:

  1. wip 变量的作用?
  2. request 方法在哪里调用的?

先看第一个问题:

drain

        void drain() {
            // 将值加 1,返回未加 1 之前的值
            // 就是判断 wip 的引用值是否是0,然后加1
            if (wip.getAndIncrement() != 0) {
                return;
            }

            // 到了这里 wip 引用的值理论上为1
            // 但是多线程的情况下, onUnsubscribed 会将 wip 加 1
            int missed = 1;
            ...
	
            for (;;) {
                ...
                    
                // 将 wip 的值减 - missed
                // 这里处在一个循环中,最终 wip 的值会变成 0,missed 也会变成0,跳出循环
                missed = wip.addAndGet(-missed);
                if (missed == 0) {
                    break;
                }
            }
        }
    }

onUnsubscribed

        @Override
        void onUnsubscribed() {
            // 取消的时候,wip 的值为 0 的话,清空队列
            // 就是说,此时,drain 方法运行到了 for 循环的最后几行
            // 这里应该是为了保证,数据从队列里面取出来,一定要发送出去才行
            if (wip.getAndIncrement() == 0) {
                queue.clear();
            }
        }

在 BufferAsyncEmitter 这个类中,使用到 wip 这个变量的,只有上面这几个地方。

onUnsubscribed 会在父类的 cancel 方法中调用,所以我们调用 cancel 就会改变 wip 的值:

FlowableCreate.BaseEmitter

cancel

        @Override
        public final void cancel() {
            serial.dispose();
            onUnsubscribed();
        }

好了,第一个问题说完了,我们来看看第2个问题:

首先我们回到 demo 中,既然 create 方法中没有调用 request 的地方,那么我们只能从 subscribe 方法入手了。

Flowable

io.reactivex.Flowable#subscribe(io.reactivex.functions.Consumer<? super T>)

public final Disposable subscribe(Consumer<? super T> onNext) {
    return subscribe(onNext, Functions.ON_ERROR_MISSING,
            Functions.EMPTY_ACTION, FlowableInternalHelper.RequestMax.INSTANCE);
}

它调用了名方法:

io.reactivex.Flowable#subscribe(io.reactivex.functions.Consumer<? super T>, io.reactivex.functions.Consumer<? super java.lang.Throwable>, io.reactivex.functions.Action, io.reactivex.functions.Consumer<? super org.reactivestreams.Subscription>)

    public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError,
            Action onComplete, Consumer<? super Subscription> onSubscribe) {
        ObjectHelper.requireNonNull(onNext, "onNext is null");
        ObjectHelper.requireNonNull(onError, "onError is null");
        ObjectHelper.requireNonNull(onComplete, "onComplete is null");
        ObjectHelper.requireNonNull(onSubscribe, "onSubscribe is null");

        LambdaSubscriber<T> ls = new LambdaSubscriber<T>(onNext, onError, onComplete, onSubscribe);

        subscribe(ls);

        return ls;
    }

创建了一个 LambdaSubscriber 对象,并调用了 subscribe 方法,将 ls 传递了进去。

所以这个方法其实就是将我们的 consumer 包装成了 LambdaSubscriber,然后调用真正的 subscribe 方法。

LambdaSubscriber

看看 LambdaSubscriber 类:

构造方法

    public LambdaSubscriber(Consumer<? super T> onNext, Consumer<? super Throwable> onError,
            Action onComplete,
            Consumer<? super Subscription> onSubscribe) {
        super();
        this.onNext = onNext;
        this.onError = onError;
        this.onComplete = onComplete;
        this.onSubscribe = onSubscribe;
    }

保存了一些变量,onSubscribe 值得注意,因为这个 Consumer 在订阅的时候会回调,是调用 request 的最好时机。

直接看 onSubscribe 的实现。

onSubscribe

    @Override
    public void onSubscribe(Subscription s) {
        if (SubscriptionHelper.setOnce(this, s)) {
            try {
                onSubscribe.accept(this);
            } catch (Throwable ex) {
                Exceptions.throwIfFatal(ex);
                s.cancel();
                onError(ex);
            }
        }
    }

这里调用了 onSubscribe 对象的 accept 方法。我们看看这个对象的实现吧。

FlowableInternalHelper.RequestMax.INSTANCE

从前面的代码中(Flowable.subscribe()方法中),我们知道 onSubscribe 对象是 FlowableInternalHelper.RequestMax.INSTANCE。所以看看这个类的代码吧。

FlowableInternalHelper.RequestMax.INSTANCE

    public enum RequestMax implements Consumer<Subscription> {
        INSTANCE;
        @Override
        public void accept(Subscription t) throws Exception {
            t.request(Long.MAX_VALUE);
        }
    }

嗯,果然是这里调用了 request 方法。

到这里,Flowable 的分析就告一段落。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值