blockingFirst只会获取第一个元素,可以给出默认值,但是会阻塞调用blockingFirst()方法的线程。
int v = Observable.create((ObservableOnSubscribe<Integer>) emitter -> {
Thread.sleep(3000);
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
}).subscribeOn(Schedulers.io()).blockingFirst();
System.out.println(v);
public final T blockingFirst() {
BlockingFirstObserver<T> observer = new BlockingFirstObserver<T>();
subscribe(observer);
T v = observer.blockingGet(); //可能会被阻塞
if (v != null) {
return v;
}
throw new NoSuchElementException();
}
调用blockingFirst()方法的线程一般都会被阻塞住。看看代码是否如被阻塞的。
public final class BlockingFirstObserver<T> extends BlockingBaseObserver<T> {
@Override
public void onNext(T t) {
if (value == null) {
value = t;
upstream.dispose();
countDown(); //计数值减1,唤醒被阻塞的线程
}
}
@Override
public void onError(Throwable t) {
if (value == null) {
error = t;
}
countDown();
}
}
这里的value初始化的时候就是null,一旦被赋值,被阻塞的线程就会被唤醒。
如果熟悉CountDownLatch的就不需要看这段话了。
CountDownLatch类似与计数器,CountDownLatch有2个重要的方法await和countDown方法,调用await会被阻塞,调用countDown计数值会被减去1,一直到0就会唤醒被阻塞的线程,CountDownLatch经常用在一个线程需要等待其他线程都做完活后,自己才能做事,比如多任务下载文件,A线程下载A段,B线程下载B段,C线程下载C段,D线程需要将下载好的视频复制到目录,首先初始化CountDownLatch,计数值设置3,D线程调用await被阻塞,A线程下完后调用countDown,计数值减1,B线程下完后调用countDown,计数值减1,C线程下完后调用countDown,计数值减1,现在是计数值是0,D线程被唤醒,开始自己的任务。
public abstract class BlockingBaseObserver<T> extends CountDownLatch
implements Observer<T>, Disposable {
T value;
Throwable error;
Disposable upstream;
volatile boolean cancelled;
public BlockingBaseObserver() {
super(1);//设置计数值
}
@Override
public final void onSubscribe(Disposable d) {
this.upstream = d;
if (cancelled) {
d.dispose();
}
}
@Override
public final void onComplete() {
countDown();
}
@Override
public final void dispose() {
cancelled = true;
Disposable d = this.upstream;
if (d != null) {
d.dispose();
}
}
@Override
public final boolean isDisposed() {
return cancelled;
}
//调用该方法的线程被阻塞
public final T blockingGet() {
if (getCount() != 0) {
try {
BlockingHelper.verifyNonBlocking();
await(); //阻塞,等着计数值减为0
} catch (InterruptedException ex) {
dispose();
throw ExceptionHelper.wrapOrThrow(ex);
}
}
Throwable e = error;
if (e != null) {
throw ExceptionHelper.wrapOrThrow(e);
}
return value;
}
}
第一次执行到onNext方法,value被赋值,执行 countDown()方法,计数值为0,唤醒阻塞线程,拿到value。
blockingLast只会获取最后一个元素。
public final T blockingLast() {
BlockingLastObserver<T> observer = new BlockingLastObserver<T>();
subscribe(observer);
T v = observer.blockingGet(); //被阻塞
if (v != null) {
return v;
}
throw new NoSuchElementException();
}
public final class BlockingLastObserver<T> extends BlockingBaseObserver<T> {
@Override
public void onNext(T t) {
value = t; //每次调用,更新此值
}
@Override
public void onError(Throwable t) {
value = null;
error = t;
countDown();
}
}
BlockingLastObserver每次更新最新的值,那在那里调用 countDown()方法?
在BlockingBaseObserver里由默认的onComplete方法内部,就执行了 countDown()方法。