amb操作符的作用是让多个观察者竞争,谁赢了,谁就可以发送数据,有种胜者为王,败者为寇的感觉。
ambWith、amb、ambArray也都是差不多的,这里就拿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操作符就是看谁跑的快,只会有一个胜利者