RxJava被压模式源码分析

被压模式不了解的可以自行百度,有详细的资料,这里不再详述。RxJava中被压模式体现在使用中即Flowable+Subscrible模式。
简单的使用分为三步:
1,创建Flowable
Flowable<String> flowable = Flowable.create(new FlowableOnSubscribe<String>() {
    @Override
    public void subscribe(FlowableEmitter<String> e) throws Exception {
        e.onNext("HelloWord");
        }
    //抛弃策略
}, BackpressureStrategy.DROP);
上面是非常简单的Flowable创建过程,看创建的源码,需要传入一个FlowableOnSubscribe用于想消息队列(其实使用AtomicReferenceArray实现多线程同步)中添加消息,和一个BackpressureStrategy指定消息抛弃策略,此处我们详细讲述默认策略,其他的后续补充。
看下创建Flowable的源码:
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, moe)
);}
其实就是创建了一个FlowableCreate并返回并回了
 2,创建Subscrible  
Subscriber<String> subscriber = new Subscriber<String>() {
            Subscription subscription;
            @Override
            public void onSubscribe(Subscription s) {
    subscription.request(1);
            }
            @Override
            public void onNext(String s) {
            }
            @Override
            public void onError(Throwable e) {
                Log.i(TAG, "onError: " + e.getLocalizedMessage());
            }
            @Override
            public void onComplete() {
    subscription.cancel();
            }
        };
3,把两者联系起来
flowable.subscribe(subscriber);
来看源码:
  s = RxJavaPlugins.onSubscribe(this, s);
  ObjectHelper.requireNonNull(s, "Plugin returned null Subscriber");
  subscribeActual(s);
  主要是者三行代码实现绑定,
  看第一句源码:
  public static <T> Subscriber<? super T> onSubscribe(Flowable<T> source, Subscriber<? super T> subscriber) {
   BiFunction<Flowable, Subscriber, Subscriber> f = onFlowableSubscribe;
   if (f != null) {
    return apply(f, source, subscriber);
   }
   return subscriber;
  }
  是设计用来在真正绑定之前让我们对所有的订阅者做拦截,可以对其做相应的处理,当然如果不需要我们也可以不设置
  就直接返回。
  第二句用于判空抛异常,这种写法会优美一些,也方便对异常的统一处理。
  第三句调用subscribeActual(s)方法,并把Subscriber传下去,subscribeActual(s)是一个抽象方法,我们直接看其在FlowableCreate
  中的实现:
  @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。
 @Override
 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); //code1
  drain();  //code2
 }
 可以看到onNext做了两件事,首先code1向消息队列中添加消息,code2的作用是从消息队列中拿消息给Subscriber执行,下面我们重点分析下这个方法(这段逻辑
 的设计也是让我眼前一亮):
 
 void drain() {
  if (wip.getAndIncrement() != 0) {
   return;
  }
  int missed = 1;
  ...
  ...
  for(;;){
   missed = wip.addAndGet(-missed);
   if (missed == 0) {
    break;
   }
  }
 }
 先来看这个地方,wip是AtomicInteger类型,保证自增的原子性操作,这个地方保证了,同一时间只有一个线程在操作循环消息队列取出消息,作用类似于添加synchronized,
 当然只是类似。可以看到如果wip不等0,说明还有线程在操作消息队列,就把wip加1返回,表示我要取消息,但是检测都有线程正在取,就把标记wip自增1,然后在最后等本次
 操作结束后调用wip.addAndGet(-missed)实际就是(wip-1)如果等于0就结束退出,如果大于0,说明有错过的请求,再次循环,直到wip等0.那么为什么会有这样的设计呢,为什
 么不是,一次把所有请求都执行呢,其实这个跟Flowable的消息存取模式有关。我们先来看下Subscription的request接口的介绍:
 /**
     * No events will be sent by a {@link Publisher} until demand is signaled via this method.
     * <p>
     * It can be called however often and whenever needed—but the outstanding cumulative demand must never exceed Long.MAX_VALUE.
     * An outstanding cumulative demand of Long.MAX_VALUE may be treated by the {@link Publisher} as "effectively unbounded".
     * <p>
     * Whatever has been requested can be sent by the {@link Publisher} so only signal demand for what can be safely handled.
     * <p>
     * A {@link Publisher} can send less than is requested if the stream ends but
     * then must emit either {@link Subscriber#onError(Throwable)} or {@link Subscriber#onComplete()}.
     *
     * @param n the strictly positive number of elements to requests to the upstream {@link Publisher}
     */
    public void request(long n);
 
 讲的很明白,消费端(Subscriber)只有调用了request方法,服务端(Flowable)才会发射数据,也就是说在Flowable中调用FlowableEmitter的onNext方法,只是把消息放到消息
 队列,如果Subscriber中不调用Subscription的request方法,是不会发送消息的。那么我们看下request的实现:
 @Override
     public final void request(long n) {
  if (SubscriptionHelper.validate(n)) {
   BackpressureHelper.add(this, n);//code1
   onRequested();     //code2
  }
 }
 request方法的实现在父类BaseEmitter中,本身继承了AtomicLong,code1的作用是把自己的值加上要请求的数量的结果赋值给自己(前面讲到自己本身也是AtomicLong),然后调用 onRequested()
 方法,看下 onRequested()的具体实现:
  @Override
        void onRequested() {
            drain();
        }
 看到有调用了drain();方法,那么我们接着看drain()是如何取消息的:
 void drain() {
            if (wip.getAndIncrement() != 0) {
                return;
            }
            int missed = 1;
            final Subscriber<? super T> a = actual;
            final SpscLinkedArrayQueue<T> q = queue;
            for (;;) {
                long r = get();
                long e = 0L;
                while (e != r) {
                    ...
                    boolean d = done;
                    T o = q.poll();
     
                    boolean empty = o == null;
     
     ...
     if (empty) {
                        break;
                    }
                    ...
                    a.onNext(o);
                    e++;
                }
    ...
                if (e != 0) {
                    BackpressureHelper.produced(this, e);
                }
                missed = wip.addAndGet(-missed);
                if (missed == 0) {
                    break;
                }
            }
        }
 仅摘取了关键代码,可以看到早while循环中,只有当e != r才会进入取消息执行,那么r的值是什么呢,其实他就是我们前面说到的request请求的值,我们说过他本身就是一个AtomicLong
 理解了这里就知道为什么不调用request就不会发消息了吧。在往下看:
    if (e != 0) {
                    BackpressureHelper.produced(this, e);
                }
 这段逻辑是把已经处理的消息减去,其实就是request请求的数据条数减去已经处理的数据条数。
     if (empty) {
                        break;
                    }
 可以看到如果发起request(int n)请求的时候消息队列为空就返回,但是这时要请求的数据条数已经是n了,即long r = get() r等于n,所以当有消息添加的时候会立刻执行。这个设计是不是
 很巧妙地实现了消息队列阻塞的功能又没有任何开销。
 
 好了到这里被压模式基本介绍完了,有不少地方没有详尽介绍,需要自行阅读源码,不好的地方,不喜勿喷。
 
 
 
  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值