Rxjava2 amb操作符

395 阅读1分钟

amb操作符的作用是让多个观察者竞争,谁赢了,谁就可以发送数据,有种胜者为王,败者为寇的感觉。 ambWithambambArray也都是差不多的,这里就拿ambArray举个例子。

 Observable<Integer> observable1 = Observable.timer(4, TimeUnit.SECONDS)
                .flatMap(__ -> Observable.just(1, 2, 3, 4, 5));

        Observable<Integer> observable2 = Observable.timer(3, TimeUnit.SECONDS)
                .flatMap(__ -> Observable.just(6, 7, 8, 9, 10));

        Observable<Integer> observable3 = Observable.timer(2, TimeUnit.SECONDS)
                .flatMap(__ -> Observable.just(11, 12, 13, 14, 15));

        Observable.ambArray(observable1, observable2, observable3)
                .subscribe(next -> Logger.getGlobal().info("OnNext: next: " + next));

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
  public static <T> Observable<T> ambArray(ObservableSource<? extends T>... sources) {
        ...
        int len = sources.length;
        if (len == 0) {
            return empty();
        }
        if (len == 1) {
            return (Observable<T>)wrap(sources[0]);
        }
        return RxJavaPlugins.onAssembly(new ObservableAmb<T>(sources, null));
    }

当我们调用subscribe方法时,就会执行subscribeActual方法。

 public void subscribeActual(Observer<? super T> observer) {
        ObservableSource<? extends T>[] sources = this.sources;
        int count = 0;
        ...省略代码...
        
        count = sources.length;

         ...省略代码...

        AmbCoordinator<T> ac = new AmbCoordinator<T>(observer, count);
        ac.subscribe(sources);
    }

AmbCoordinator内部

public void subscribe(ObservableSource<? extends T>[] sources) {
            AmbInnerObserver<T>[] as = observers;
            int len = as.length;
            for (int i = 0; i < len; i++) {
                as[i] = new AmbInnerObserver<T>(this, i + 1, downstream);
            }
            //初始化0,表示还没有胜利者
            winner.lazySet(0); // release the contents of 'as'
            downstream.onSubscribe(this);

           
            for (int i = 0; i < len; i++) {
              
                if (winner.get() != 0) {
                  // 如果已经有胜利者了,也就不需要给后面订阅了
                    return;
                }
				//开始准备调用next方法了
                sources[i].subscribe(as[i]);
            }
 }
 
  
  public boolean win(int index) {
            int w = winner.get();
            if (w == 0) {
                 //等于0表示此时还没有胜利者,大家都平等,开始竞争
                if (winner.compareAndSet(0, index)) {
                    //这里的期望值是0,希望更新的值是index,如果顺利,compareAndSet就会返回true
                    //如果这个时候,有别的线程进入,修改了winner的内部值,与期望值0不匹配,compareAndSet就会返回false
                    AmbInnerObserver<T>[] a = observers;
                    int n = a.length;
                    for (int i = 0; i < n; i++) {
                        //如果顺利到这,就说明赢了,其他的就需要dispose了,事件也就不会再发送了
                        if (i + 1 != index) {
                            a[i].dispose();
                        }
                    }
                    return true;
                }
                return false;
            }
            return w == index;
        }
 

构造AmbInnerObserver对象,winner表示胜利者,是一个原子变量,存储的是index,就是靠这个index来表示是否已经有胜利者

 static final class AmbInnerObserver<T> extends AtomicReference<Disposable> implements Observer<T> {

        private static final long serialVersionUID = -1185974347409665484L;
        final AmbCoordinator<T> parent;
        final int index;
        final Observer<? super T> downstream;

        boolean won;

        AmbInnerObserver(AmbCoordinator<T> parent, int index, Observer<? super T> downstream) {
            this.parent = parent;
            this.index = index;
            this.downstream = downstream;
        }

     ...

        @Override
        public void onNext(T t) {
            if (won) {
            //已经赢了,就会直接发送事件
                downstream.onNext(t);
            } else {
                 //开始竞争
                if (parent.win(index)) {
                    //只有胜利者才能发送事件
                    won = true;
                    downstream.onNext(t);
                } else {
                  //竞争失败自己dispose
                    get().dispose();
                }
            }
        }

      ...
    }

所以amb操作符就是看谁跑的快,只会有一个胜利者