难道这样就够了吗?不,远远不够!
提前多熟悉阿里往年的面试题肯定是对面试有很大的帮助的,但是作为技术性职业,手里有实打实的技术才是你面对面试官最有用的利器,这是从内在散发出来的自信。
备战阿里时我花的最多的时间就是在学习技术上,占了我所有学习计划中的百分之70,这是一些我学习期间觉得还是很不错的一些学习笔记
我为什么要写这篇文章呢,其实我觉得学习是不能停下脚步的,在网络上和大家一起分享,一起讨论,不单单可以遇到更多一样的人,还可以扩大自己的眼界,学习到更多的技术,我还会在csdn、博客、掘金等网站上分享技术,这也是一种学习的方法。
今天就分享到这里了,谢谢大家的关注,以后会分享更多的干货给大家!
例子如下,源头Observable
发送的是String类型的数字,利用map转换成int型,最终在终点Observer
接受到的也是int类型数据。:
final Observable testCreateObservable = Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
e.onNext(“1”);
e.onComplete()
}
});
Observable map = testCreateObservable.map(new Function<String, Integer>() {
@Override
public Integer apply(String s) throws Exception {
return Integer.parseInt(s);
}
});
map.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, “onSubscribe() called with: d = [” + d + “]”);
}
@Override
public void onNext(Integer value) {
Log.d(TAG, “onNext() called with: value = [” + value + “]”);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, “onError() called with: e = [” + e + “]”);
}
@Override
public void onComplete() {
Log.d(TAG, “onComplete() called”);
}
});
我们看一下map
函数的源码:
public final Observable map(Function<? super T, ? extends R> mapper) {
//判空略过
ObjectHelper.requireNonNull(mapper, “mapper is null”);
//RxJavaPlugins.onAssembly()是hook 上文提到过
return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));
}
RxJavaPlugins.onAssembly()
是hook 上文提到过,所以我们只要看ObservableMap
,它就是返回到我们手里的Observable
:
public final class ObservableMap<T, U> extends AbstractObservableWithUpstream<T, U> {
//将function变换函数类保存起来
final Function<? super T, ? extends U> function;
public ObservableMap(ObservableSource source, Function<? super T, ? extends U> function) {
//super()将上游的Observable保存起来 ,用于subscribeActual()中用。
super(source);
this.function = function;
}
@Override
public void subscribeActual(Observer<? super U> t) {
source.subscribe(new MapObserver<T, U>(t, function));
}
它继承自AbstractObservableWithUpstream
,该类继承自Observable
,很简单,就是将上游的ObservableSource
保存起来,做一次wrapper,所以它也算是装饰者模式的提现,如下:
abstract class AbstractObservableWithUpstream<T, U> extends Observable implements HasUpstreamObservableSource {
//将上游的ObservableSource
保存起来
protected final ObservableSource source;
AbstractObservableWithUpstream(ObservableSource source) {
this.source = source;
}
@Override
public final ObservableSource source() {
return source;
}
}
关于ObservableSource
,代表了一个标准的无背压的 源数据接口,可以被Observer
消费(订阅),如下:
public interface ObservableSource {
void subscribe(Observer<? super T> observer);
}
所有的Observable
都已经实现了它,所以我们可以认为Observable
和ObservableSource
在本文中是相等的:
public abstract class Observable implements ObservableSource {
所以我们得到的ObservableMap
对象也很简单,就是将上游的Observable
和变换函数类Function
保存起来。
Function
的定义超级简单,就是一个接口,给我一个T,还你一个R.
public interface Function<T, R> {
R apply(T t) throws Exception;
}
本例写的是将String->int.
重头戏,subscribeActual()
是订阅真正发生的地方,ObservableMap
如下编写,就一句话,用MapObserver订阅上游Observable。:
@Override
public void subscribeActual(Observer<? super U> t) {
//用MapObserver订阅上游Observable。
source.subscribe(new MapObserver<T, U>(t, function));
}
MapObserver
也是装饰者模式,对终点(下游)Observer
修饰。
static final class MapObserver<T, U> extends BasicFuseableObserver<T, U> {
final Function<? super T, ? extends U> mapper;
MapObserver(Observer<? super U> actual, Function<? super T, ? extends U> mapper) {
//super()将actual保存起来
super(actual);
//保存Function变量
this.mapper = mapper;
}
@Override
public void onNext(T t) {
//done在onError 和 onComplete以后才会是true,默认这里是false,所以跳过
if (done) {
return;
}
//默认sourceMode是0,所以跳过
if (sourceMode != NONE) {
actual.onNext(null);
return;
}
//下游Observer接受的值
U v;
//这一步执行变换,将上游传过来的T,利用Function转换成下游需要的U。
try {
v = ObjectHelper.requireNonNull(mapper.apply(t), “The mapper function returned a null value.”);
} catch (Throwable ex) {
fail(ex);
return;
}
//变换后传递给下游Observer
actual.onNext(v);
}
到此我们梳理一下流程:
订阅的过程,是从下游到上游依次订阅的。
-
即终点
Observer
订阅了map
返回的ObservableMap
。 -
然后
map
的Observable
(ObservableMap
)在被订阅时,会订阅其内部保存上游Observable
,用于订阅上游的Observer
是一个装饰者(MapObserver
),内部保存了下游(本例是终点)Observer
,以便上游发送数据过来时,能传递给下游。 -
以此类推,直到源头
Observable
被订阅,根据上节课内容,它开始向Observer发送数据。
数据传递的过程,当然是从上游push到下游的,
-
源头
Observable
传递数据给下游Observer
(本例就是MapObserver
) -
然后
MapObserver
接收到数据,对其变换操作后(实际的function在这一步执行),再调用内部保存的下游Observer
的onNext()
发送数据给下游 -
以此类推,直到终点
Observer
。
线程调度subscribeOn
简化问题,代码如下:
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
Log.d(TAG, “subscribe() called with: e = [” + e + “]” + Thread.currentThread());
e.onNext(“1”);
e.onComplete();
}
//只是在Observable和Observer之间增加了一句线程调度代码
}).subscribeOn(Schedulers.io())
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, “onSubscribe() called with: d = [” + d + “]”);
}
@Override
public void onNext(String value) {
Log.d(TAG, “onNext() called with: value = [” + value + “]”);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, “onError() called with: e = [” + e + “]”);
}
@Override
public void onComplete() {
Log.d(TAG, “onComplete() called”);
}
});
只是在Observable
和Observer
之间增加了一句线程调度代码:.subscribeOn(Schedulers.io())
.
查看subscribeOn()
源码:
public final Observable subscribeOn(Scheduler scheduler) {
//判空略过
ObjectHelper.requireNonNull(scheduler, “scheduler is null”);
//抛开Hook,重点还是ObservableSubscribeOn
return RxJavaPlugins.onAssembly(new ObservableSubscribeOn(this, scheduler));
}
等等,怎么有种似曾相识的感觉,大家可以把文章向上翻,看看map()
的源码。
和subscribeOn()
的套路如出一辙,那么我们根据上面的结论,
先猜测**ObservableSubscribeOn
类也是一个包装类(装饰者)**,点进去查看:
public final class ObservableSubscribeOn extends AbstractObservableWithUpstream<T, T> {
//保存线程调度器
final Scheduler scheduler;
public ObservableSubscribeOn(ObservableSource source, Scheduler scheduler) {
//map的源码中我们分析过,super()只是简单的保存ObservableSource
super(source);
this.scheduler = scheduler;
}
@Override
public void subscribeActual(final Observer<? super T> s) {
//1 创建一个包装Observer
final SubscribeOnObserver parent = new SubscribeOnObserver(s);
//2 手动调用 下游(终点)Observer.onSubscribe()方法,所以onSubscribe()方法执行在 订阅处所在的线程
s.onSubscribe(parent);
//3 setDisposable()是为了将子线程的操作加入Disposable管理中
parent.setDisposable(scheduler.scheduleDirect(new Runnable() {
@Override
public void run() {
//4 此时已经运行在相应的Scheduler 的线程中
source.subscribe(parent);
}
}));
}
和map套路大体一致,ObservableSubscribeOn
自身同样是个包装类,同样继承AbstractObservableWithUpstream
。
创建了一个SubscribeOnObserver
类,该类按照套路,应该也是实现了Observer
、Disposable
接口的包装类,让我们看一下:
static final class SubscribeOnObserver extends AtomicReference implements Observer, Disposable {
//真正的下游(终点)观察者
final Observer<? super T> actual;
//用于保存上游的Disposable,以便在自身dispose时,连同上游一起dispose
final AtomicReference s;
SubscribeOnObserver(Observer<? super T> actual) {
this.actual = actual;
this.s = new AtomicReference();
}
@Override
public void onSubscribe(Disposable s) {
//onSubscribe()方法由上游调用,传入Disposable。在本类中赋值给this.s,加入管理。
DisposableHelper.setOnce(this.s, s);
}
//直接调用下游观察者的对应方法
@Override
public void onNext(T t) {
actual.onNext(t);
}
@Override
public void onError(Throwable t) {
actual.onError(t);
}
@Override
public void onComplete() {
actual.onComplete();
}
//取消订阅时,连同上游Disposable一起取消
@Override
public void dispose() {
DisposableHelper.dispose(s);
DisposableHelper.dispose(this);
}
@Override
public boolean isDisposed() {
return DisposableHelper.isDisposed(get());
}
//这个方法在subscribeActual()中被手动调用,为了将Schedulers返回的Worker加入管理
void setDisposable(Disposable d) {
DisposableHelper.setOnce(this, d);
}
}
这两个类根据上一节的铺垫加上注释,其他都好理解,稍微不好理解的应该是下面两句代码:
//ObservableSubscribeOn类
//3 setDisposable()是为了将子线程的操作加入Disposable管理中
parent.setDisposable(scheduler.scheduleDirect(new Runnable() {
@Override
public void run() {
//4 此时已经运行在相应的Scheduler 的线程中
source.subscribe(parent);
}
}));
//SubscribeOnObserver类
//这个方法在subscribeActual()中被手动调用,为了将Schedulers返回的Worker加入管理
void setDisposable(Disposable d) {
DisposableHelper.setOnce(this, d);
}
其中scheduler.scheduleDirect(new Runnable()..)
方法源码如下:
/**
-
Schedules the given task on this scheduler non-delayed execution.
-
…
*/
public Disposable scheduleDirect(Runnable run) {
return scheduleDirect(run, 0L, TimeUnit.NANOSECONDS);
}
从注释和方法名我们可以看出,这个传入的Runnable
会立刻执行。
再继续往里面看:
public Disposable scheduleDirect(Runnable run, long delay, TimeUnit unit) {
//class Worker implements Disposable ,Worker本身是实现了Disposable
final Worker w = createWorker();
//hook略过
final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
//开始在Worker的线程执行任务,
w.schedule(new Runnable() {
@Override
public void run() {
try {
//调用的是 run()不是 start()方法执行的线程的方法。
decoratedRun.run();
} finally {
//执行完毕会 dispose()
w.dispose();
}
}
}, delay, unit);
//返回Worker对象
return w;
}
createWorker()
是一个抽象方法,由具体的Scheduler
类实现,例如IoScheduler
对应的Schedulers.io()
.
public abstract Worker createWorker();
初看源码,为了了解大致流程,不宜过入深入,先点到为止。
OK,现在我们总结一下scheduler.scheduleDirect(new Runnable()..)
的重点:
-
传入的
Runnable
是立刻执行的。 -
返回的**
Worker
对象就是一个Disposable
对象**, -
Runnable
执行时,是直接手动调用的run()
,而不是start()
方法. -
上一点应该是为了,能控制在
run()
结束后(包括异常终止),都会自动执行Worker
.dispose()
.
而返回的**Worker
对象**也会被parent.setDisposable(...)
加入管理中,以便在手动dispose()
时能取消线程里的工作。
我们总结一下subscribeOn(Schedulers.xxx())
的过程:
-
返回一个
ObservableSubscribeOn
包装类对象 -
上一步返回的对象被订阅时,回调该类中的
subscribeActual()
方法,在其中会立刻将线程切换到对应的Schedulers.xxx()
线程。 -
在切换后的线程中,执行
source.subscribe(parent);
,对上游(终点)Observable
订阅 -
上游(终点)
Observable
开始发送数据,根据RxJava2 源码解析(一),上游发送数据仅仅是调用下游观察者对应的onXXX()
方法而已,所以此时操作是在切换后的线程中进行。
一点扩展,
大家可能看过一个结论:
subscribeOn(Schedulers.xxx())
切换线程N次,总是以第一次为准,或者说离源Observable最近的那次为准,并且对其上面的代码生效(这一点对比的ObserveOn()
)。
为什么?
- 因为根据RxJava2 源码解析(一)中提到,订阅流程从下游往上游传递
- 在subscribeActual()
里开启了Scheduler的工作,source.subscribe(parent);
,从这一句开始切换了线程,所以在这之上的代码都是在切换后的线程里的了。
- 但如果连续切换,最上面的切换最晚执行,此时线程变成了最上面的subscribeOn(xxxx)
指定的线程,
- 而数据push时,是从上游到下游的,所以会在离源头最近的那次subscribeOn(xxxx)
的线程里push数据(onXXX()
)给下游。
可写如下代码验证:
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
Log.d(TAG, “subscribe() called with: e = [” + e + “]” + Thread.currentThread());
e.onNext(“1”);
e.onComplete();
}
}).subscribeOn(Schedulers.io())
.map(new Function<String, String>() {
@Override
public String apply(String s) throws Exception {
//依然是io线程
Log.d(TAG, “apply() called with: s = [” + s + “]” + Thread.currentThread());
return s;
}
})
.subscribeOn(Schedulers.computation())
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, “onSubscribe() called with: d = [” + d + “]”);
}
@Override
public void onNext(String value) {
Log.d(TAG, “onNext() called with: value = [” + value + “]”);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, “onError() called with: e = [” + e + “]”);
}
@Override
public void onComplete() {
Log.d(TAG, “onComplete() called”);
}
});
线程调度observeOn
在上一节的基础上,增加一个observeOn(AndroidSchedulers.mainThread())
,就完成了观察者线程的切换。
.subscribeOn(Schedulers.computation())
//在上一节的基础上,增加一个ObserveOn
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
继续看源码吧,我已经能猜出来了,hook+new XXXObservable();
一线互联网大厂Java核心面试题库
正逢面试跳槽季,给大家整理了大厂问到的一些面试真题,由于文章长度限制,只给大家展示了部分题目,更多Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等已整理上传,感兴趣的朋友可以看看支持一波!
d onError(Throwable e) {
Log.d(TAG, “onError() called with: e = [” + e + “]”);
}
@Override
public void onComplete() {
Log.d(TAG, “onComplete() called”);
}
});
线程调度observeOn
在上一节的基础上,增加一个observeOn(AndroidSchedulers.mainThread())
,就完成了观察者线程的切换。
.subscribeOn(Schedulers.computation())
//在上一节的基础上,增加一个ObserveOn
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
继续看源码吧,我已经能猜出来了,hook+new XXXObservable();
一线互联网大厂Java核心面试题库
[外链图片转存中…(img-tdaazmN6-1714869463854)]
正逢面试跳槽季,给大家整理了大厂问到的一些面试真题,由于文章长度限制,只给大家展示了部分题目,更多Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等已整理上传,感兴趣的朋友可以看看支持一波!