RxJava系列6(从微观角度解读RxJava源码)
- RxJava系列1(简介)
- RxJava系列2(基本概念及使用介绍)
- RxJava系列3(转换操作符)
- RxJava系列4(过滤操作符)
- RxJava系列5(组合操作符)
- RxJava系列6(从微观角度解读RxJava源码)
- RxJava系列7(最佳实践)
前言
通过前面五个篇幅的介绍,相信大家对RxJava的基本使用以及操作符应该有了一定的认识。但是知其然还要知其所以然;所以从这一章开始我们聊聊源码,分析RxJava的实现原理。本文我们主要从三个方面来分析RxJava的实现:
- RxJava基本流程分析
- 操作符原理分析
- 线程调度原理分析
本章节基于RxJava1.1.9版本的源码
一、RxJava执行流程分析
在RxJava系列2(基本概念及使用介绍)中我们介绍过,一个最基本的RxJava调用是这样的:
示例A
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello RxJava!");
subscriber.onCompleted();
}
}).subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
System.out.println("completed!");
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
System.out.println(s);
}
});
首先调用Observable.create()
创建一个被观察者Observable
,同时创建一个OnSubscribe
作为create()
方法的入参;接着创建一个观察者Subscriber
,然后通过subseribe()
实现二者的订阅关系。这里涉及到三个关键对象和一个核心的方法:
- Observable(被观察者)
- OnSubscribe (从纯设计模式的角度来理解,
OnSubscribe.call()
可以看做是观察者模式中被观察者用来通知观察者的notifyObservers()
方法) - Subscriber (观察者)
- subscribe() (实现观察者与被观察者订阅关系的方法)
1、Observable.create()源码分析
首先我们来看看Observable.create()
的实现:
public static <T> Observable<T> create(OnSubscribe<T> f) {
return new Observable<T>(RxJavaHooks.onCreate(f));
}
这里创建了一个被观察者Observable
,同时将RxJavaHooks.onCreate(f)
作为构造函数的参数,源码如下:
protected Observable(OnSubscribe<T> f) {
this.onSubscribe = f;
}
我们看到源码中直接将参数RxJavaHooks.onCreate(f)
赋值给了当前我们构造的被观察者Observable
的成员变量onSubscribe
。那么RxJavaHooks.onCreate(f)
返回的又是什么呢?我们接着往下看:
public static <T> Observable.OnSubscribe<T> onCreate(Observable.OnSubscribe<T> onSubscribe) {
Func1<OnSubscribe, OnSubscribe> f = onObservableCreate;
if (f != null) {
return f.call(onSubscribe);
}
return onSubscribe;
}
由于我们并没调用RxJavaHooks.initCreate()
,所以上面代码中的onObservableCreate
为null;因此RxJavaHooks.onCreate(f)
最终返回的就是f
,也就是我们在Observable.create()
的时候new出来的OnSubscribe
。(由于对RxJavaHooks的理解并不影响我们对RxJava执行流程的分析,因此在这里我们不做进一步的探讨。为了方便理解我们只需要知道RxJavaHooks一系列方法的返回值就是入参本身就OK了,例如这里的RxJavaHooks.onCreate(f)
返回的就是f
)。
至此我们做下逻辑梳理:Observable.create()
方法构造了一个被观察者Observable
对象,同时将new出来的OnSubscribe
赋值给了该Observable
的成员变量onSubscribe
。
2、Subscriber源码分析
接着我们看下观察者Subscriber
的源码,为了增加可读性,我去掉了源码中的注释和部分代码。
public abstract class Subscriber<T> implements Observer<T>, Subscription {
private final SubscriptionList subscriptions;//订阅事件集,所有发送给当前Subscriber的事件都会保存在这里
...
protected Subscriber(Subscriber<?> subscriber, boolean shareSubscriptions) {
this.subscriber = subscriber;
this.subscriptions = shareSubscriptions && subscriber != null ? subscriber.subscriptions : new SubscriptionList();
}
...
@Override
public final void unsubscribe() {
subscriptions.unsubscribe();
}
@Override
public final boolean isUnsubscribed() {
return subscriptions.isUnsubscribed();
}
public void onStart() {
}
...
}
public interface Subscription {
void unsubscribe();
boolean isUnsubscribed();
}
Subscriber
实现了Subscription
接口,从而对外提供isUnsubscribed()
和unsubscribe()
方法。前者用于判断是否已经取消订阅;后者用于将订阅事件列表(也就是当前观察者的成员变量subscriptions
)中的所有Subscription
取消订阅,并且不再接受观察者Observable
发送的后续事件。
3、subscribe()源码分析
前面我们分析了观察者和被观察者相关的源码,那么接下来便是整个订阅流程中最最关键的环节了。
public final Subscription subscribe(Subscriber<? super T> subscriber) {
return Observable.subscribe(subscriber, this);
}
static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {
...
subscriber.onStart();
if (!(subscriber instanceof SafeSubscriber)) {
subscriber = new SafeSubscriber<T>(subscriber);
}
try {
RxJavaHooks.onObservableStart(observable, observable.onSubscribe).call(subscriber);
return RxJavaHooks.onObservableReturn(subscriber);
} catch (Throwable e) {
...
return Subscriptions.unsubscribed();
}
}
subscribe()
方法中将传进来的subscriber
包装成了SafeSubscriber
,SafeSubscriber
其实是subscriber
的一个代理,对subscriber
的一系列方法做了更加严格的安全校验。保证了onCompleted()
和onError()
只会有一个被执行且只执行一次,一旦它们其中方法被执行过后onNext()
就不在执行了。
上述代码中最关键的就是RxJavaHooks.onObservableStart(observable, observable.onSubscribe).call(subscriber)
。这里的RxJavaHooks和之前提到的一样,RxJavaHooks.onObservableStart(observable, observable.onSubscribe)
返回的正是他的第二个入参observable.onSubscribe
,也就是当前observable
的成员变量onSubscribe
。而这个成员变量我们前面提到过,它是我们在Observable.create()
的时候new出来的。所以这段代码可以简化为onSubscribe.call(subscriber)
。这也印证了我在RxJava系列2(基本概念及使用介绍)中说的,onSubscribe.call(subscriber)
中的subscriber
正是我们在subscribe()
方法中new出来的观察者。
到这里,我们对RxJava的执行流程做个总结:首先我们调用crate()
创建一个观察者,同时创建一个OnSubscribe
作为该方法的入参;接着调用subscribe()
来订阅我们自己创建的观察者Subscriber
。
一旦调用subscribe()
方法后就会触发执行OnSubscribe.call()
。然后我们就可以在call方法调用观察者subscriber
的onNext()
,onCompleted()
,onError()
。
最后我用张图来总结下之前的分析结果:
二、操作符原理分析
之前我们介绍过几十个操作符,要一一分析它们的源码显然不太现实。在这里我抛砖引玉,选取一个相对简单且常用的map
操作符来分析。
我们先来看一个map
操作符的简单应用:
示例B
Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
subscriber.onNext(1);
subscriber.onCompleted();
}
}).map(new Func1<Integer, String>() {
@Override
public String call(Integer integer) {
return "This is " + integer;
}
}).subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
System.out.println("onCompleted!");
}
@Override
public void onError(Throwable e) {
System.out.println(e.getMessage());
}
@Override
public void onNext(String s) {
System.out.println(s);
}
});
为了便于表述,我将上面的代码做了如下拆解:
Observable<Integer> observableA = Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
subscriber.onNext(1);
subscriber.onCompleted();
}
});
Subscriber<String> subscriberOne = new Subscriber<String>() {
@Override
public void onCompleted() {
System.out.println("onCompleted!");
}
@Override
public void onError(Throwable e) {
System.out.println(e.getMessage());
}
@Override
public void onNext(String s) {
System.out.println(s);
}
};
Observable<String> observableB =
observableA.map(new Func1<Integer, String>() {
@Override
public String call(Integer integer) {
return "This is " + integer;;
}
});
observableB.subscribe(subscriberOne);
map()
的源码和上一小节介绍的create()
一样位于Observable
这个类中。
public final <R> Observable<R> map(Func1<? super T, ? extends R> func) {
return create(new OnSubscribeMap<T, R>(this, func));
}
通过查看源码我们发现调用map()
的时候实际上是创建了一个新的被观察者Observable
,我们姑且称它为ObservableB
;一开始通过Observable.create()
创建的Observable
我们称之为ObservableA
。在创建ObservableB
的时候同时创建了一个OnSubscribeMap
,而ObservableA
和变换函数Func1
则作为构造OnSubscribeMap
的参数。
public final class OnSubscribeMap<T, R> implements OnSubscribe<R> {
final Observable<T> source;//ObservableA
final Func1<? super T, ? extends R> transformer;//map操作符中的转换函数Func1。T为转换前的数据类型,在上面的例子中为Integer;R为转换后的数据类型,在该例中为String。
public OnSubscribeMap(Observable<T> source, Func1<? super T, ? extends R> transformer) {
this.source = source;
this.transformer = transformer;
}
@Override
public void call(final Subscriber<? super R> o) {//结合第一小节的分析结果,我们知道这里的入参o其实就是我们自己new的观察者subscriberOne。
MapSubscriber<T, R> parent = new MapSubscriber<T, R>(o, transformer);
o.add(parent);
source.unsafeSubscribe(parent);
}
static final class MapSubscriber<T, R> extends Subscriber<T> {
final Subscriber<? super R> actual;//这里的actual就是我们在调用subscribe()时创建的观察者mSubscriber
final Func1<? super T, ? extends R> mapper;//变换函数
boolean done;
public MapSubscriber(Subscriber<? super R> actual, Func1<? super T, ? extends R> mapper) {
this.actual = actual;
this.mapper = mapper;
}
@Override
public void onNext(T t) {
R result;
try {
result = mapper.call(t);
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
unsubscribe();
onError(OnErrorThrowable.addValueAsLastCause(ex, t));
return;
}
actual.onNext(result);
}
@Override
public void onError(Throwable e) {
...
actual.onError(e);
}
@Override
public void onCompleted() {
...
actual.onCompleted();
}
@Override
public void setProducer(Producer p) {
actual.setProducer(p);
}
}
}
OnSubscribeMap
实现了OnSubscribe
接口,因此OnSubscribeMap
就是一个OnSubscribe
。在调用map()
的时候创建了一个新的被观察者ObservableB
,然后我们用ObservableB.subscribe(subscriberOne)
订阅了观察者subscriberOne
。结合我们在第一小节的分析结果,所以OnSubscribeMap.call(o)
中的o
就是subscribe(subscriberOne)
中的subscriberOne
;一旦调用了ObservableB.subscribe(subscriberOne)
就会执行OnSubscribeMap.call()
。
在call()
方法中,首先通过我们的观察者o
和转换函数transformer
构造了一个MapSubscriber
,最后调用了source
也就是observableA
的unsafeSubscribe()
方法。即observableA
订阅了一个观察者MapSubscriber
。
public final Subscription unsafeSubscribe(Subscriber<? super T> subscriber) {
try {
...
RxJavaHooks.onObservableStart(this, onSubscribe).call(subscriber);
return RxJavaHooks.onObservableReturn(subscriber);
} catch (Throwable e) {
...
return Subscriptions.unsubscribed();
}
}
上面这段代码最终执行了onSubscribe
也就是OnSubscribeMap
的call()
方法,call()
方法中的参数就是之前在OnSubscribeMap.call()
中new出来的MapSubscriber
。最后在call()
方法中执行了我们自己的业务代码:
subscriber.onNext(1);
subscriber.onCompleted();
其实也就是执行了MapSubscriber
的onNext()
和onCompleted()
。
@Override
public void onNext(T t) {
R result;
try {
result = mapper.call(t);
} catch (Throwable ex) {
...
return;
}
actual.onNext(result);
}
onNext(T t)
方法中的的mapper
就是变换函数,actual
就是我们在调用subscribe()
时创建的观察者subscriberOne
。这个T
就是我们例子中的Integer
,R
就是String
。在onNext()
中首先调用变换函数mapper.call()
将T
转换成R
(在我们的例子中就是将Integer
类型的1转换成了String
类型的“This is 1”);接着调用subscriberOne.onNext(String result)
。同样在调用MapSubscriber.onCompleted()
时会执行subscriberOne.onCompleted()
。这样就完成了一直完成的调用流程。
我承认太啰嗦了,花费了这么大的篇幅才将map()
的转换原理解释清楚。我也是希望尽量的将每个细节都呈现出来方便大家理解,如果看我啰嗦了这么久还是没能理解,请看下面我画的这张执行流程图。
三、线程调度原理分析
在前面的文章中我介绍过RxJava可以很方便的通过subscribeOn()
和observeOn()
来指定数据流的每一部分运行在哪个线程。其中subscribeOn()
指定了处理Observable
的全部的过程(包括发射数据和通知)的线程;observeOn()
指定了观察者的onNext()
, onError()
和onCompleted()
执行的线程。接下来我们就分析分析源码,看看线程调度是如何实现的。
在分析源码前我们先看看一段常见的通过RxJava实现的线程调度代码:
示例C
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello RxJava!");
subscriber.onCompleted();
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
System.out.println("completed!");
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
System.out.println(s);
}
});
1、subscribeOn()源码分析
public final Observable<T> subscribeOn(Scheduler scheduler) {
...
return create(new OperatorSubscribeOn<T>(this, scheduler));
}
通过上面的代码我们可以看到,subscribeOn()
和map()
一样是创建了一个新的被观察者Observable
。因此我大致就能猜到subscribeOn()
的执行流程应该和map()
差不多,OperatorSubscribeOn
肯定也是一个OnSubscribe
。那我们接下来就看看OperatorSubscribeOn
的源码:
public final class OperatorSubscribeOn<T> implements OnSubscribe<T> {
final Scheduler scheduler;//线程调度器,用来指定订阅事件发送、处理等所在的线程
final Observable<T> source;
public OperatorSubscribeOn(Observable<T> source, Scheduler scheduler) {
this.scheduler = scheduler;
this.source = source;
}
@Override
public void call(final Subscriber<? super T> subscriber) {
final Worker inner = scheduler.createWorker();
subscriber.add(inner);
inner.schedule(new Action0() {
@Override
public void call() {
final Thread t = Thread.currentThread();
Subscriber<T> s = new Subscriber<T>(subscriber) {
@Override
public void onNext(T t) {
subscriber.onNext(t);
}
@Override
public void onError(Throwable e) {
try {
subscriber.onError(e);
} finally {
inner.unsubscribe();
}
}
@Override
public void onCompleted() {
try {
subscriber.onCompleted();
} finally {
inner.unsubscribe();
}
}
@Override
public void setProducer(final Producer p) {
subscriber.setProducer(new Producer() {
@Override
public void request(final long n) {
if (t == Thread.currentThread()) {
p.request(n);
} else {
inner.schedule(new Action0() {
@Override
public void call() {
p.request(n);
}
});
}
}
});
}
};
source.unsafeSubscribe(s);
}
});
}
}
OperatorSubscribeOn
实现了OnSubscribe
接口,call()
中对Subscriber
的处理也和OperatorMap
对Subscriber
的处理类似。首先通过scheduler
构建了一个Worker
;然后用传进来的subscriber
构造了一个新的Subscriber s
,并将s
丢到Worker.schedule()
中来处理;最后用原Observable
去订阅观察者s
。而这个Worker
就是线程调度的关键!前面的例子中我们通过subscribeOn(Schedulers.io())
指定了Observable
发射处理事件以及通知观察者的一系列操作的执行线程,正是通过这个Schedulers.io()
创建了我们前面提到的Worker
。所以我们来看看Schedulers.io()
的实现。
首先通过Schedulers.io()
获得了ioScheduler
并返回,上面的OperatorSubscribeOn
通过这个的Scheduler
的createWorker()
方法创建了我们前面提到的Worker
。
public static Scheduler io() {
return RxJavaHooks.onIOScheduler(getInstance().ioScheduler);
}
接着我们看看这个ioScheduler
是怎么来的,下面的代码向我们展现了是如何在Schedulers
的构造函数中通过RxJavaSchedulersHook.createIoScheduler()
来初始化ioScheduler
的。
private Schedulers() {
...
Scheduler io = hook.getIOScheduler();
if (io != null) {
ioScheduler = io;
} else {
ioScheduler = RxJavaSchedulersHook.createIoScheduler();
}
...
}
最终RxJavaSchedulersHook.createIoScheduler()
返回了一个CachedThreadScheduler
,并赋值给了ioScheduler
。
public static Scheduler createIoScheduler() {
return createIoScheduler(new RxThreadFactory("RxIoScheduler-"));
}
public static Scheduler createIoScheduler(ThreadFactory threadFactory) {
...
return new CachedThreadScheduler(threadFactory);
}
到这一步既然我们知道了ioScheduler
就是一个CachedThreadScheduler
,那我们就来看看它的createWorker()
的实现。
public Worker createWorker() {
return new EventLoopWorker(pool.get());
}
上面的代码向我们赤裸裸的呈现了前面OperatorSubscribeOn
中的Worker
其实就是EventLoopWorker
。我们重点要关注的是他的scheduleActual()
。
static final class EventLoopWorker extends Scheduler.Worker implements Action0 {
private final CompositeSubscription innerSubscription = new CompositeSubscription();
private final CachedWorkerPool pool;
private final ThreadWorker threadWorker;
final AtomicBoolean once;
EventLoopWorker(CachedWorkerPool pool) {
this.pool = pool;
this.once = new AtomicBoolean();
this.threadWorker = pool.get();
}
...
@Override
public Subscription schedule(final Action0 action, long delayTime, TimeUnit unit) {
...
ScheduledAction s = threadWorker.scheduleActual(new Action0() {
@Override
public void call() {
if (isUnsubscribed()) {
return;
}
action.call();
}
}, delayTime, unit);
innerSubscription.add(s);
s.addParent(innerSubscription);
return s;
}
}
通过对源码的一步步追踪,我们知道了前面OperatorSubscribeOn.call()
中的inner.schedule()
最终会执行到ThreadWorker
的scheduleActual()
方法。
public ScheduledAction scheduleActual(final Action0 action, long delayTime, TimeUnit unit) {
Action0 decoratedAction = RxJavaHooks.onScheduledAction(action);
ScheduledAction run = new ScheduledAction(decoratedAction);
Future<?> f;
if (delayTime <= 0) {
f = executor.submit(run);
} else {
f = executor.schedule(run, delayTime, unit);
}
run.add(f);
return run;
}
scheduleActual()
中的ScheduledAction
实现了Runnable
接口,通过线程池executor
最终实现了线程切换。上面便是subscribeOn(Schedulers.io())
实现线程切换的全部过程。
2、observeOn()源码分析
observeOn()
切换线程是通过lift
来实现的,相比subscribeOn()
在实现原理上相对复杂些。不过本质上最终还是创建了一个新的Observable
。
public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
...
return lift(new OperatorObserveOn<T>(scheduler, delayError, bufferSize));
}
public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
return create(new OnSubscribeLift<T, R>(onSubscribe, operator));
}
OperatorObserveOn
作为OnSubscribeLift
构造函数的参数用来创建了一个新的OnSubscribeLift
对象,接下来我们看看OnSubscribeLift
的实现:
public final class OnSubscribeLift<T, R> implements OnSubscribe<R> {
final OnSubscribe<T> parent;
final Operator<? extends R, ? super T> operator;
public OnSubscribeLift(OnSubscribe<T> parent, Operator<? extends R, ? super T> operator) {
this.parent = parent;
this.operator = operator;
}
@Override
public void call(Subscriber<? super R> o) {
try {
Subscriber<? super T> st = RxJavaHooks.onObservableLift(operator).call(o);
try {
st.onStart();
parent.call(st);
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
st.onError(e);
}
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
o.onError(e);
}
}
}
OnSubscribeLift
继承自OnSubscribe
,通过前面的分析我们知道一旦调用了subscribe()
将观察者与被观察绑定后就会触发被观察者所对应的OnSubscribe
的call()
方法,所以这里会触发OnSubscribeLift.call()
。在call()
中调用了OperatorObserveOn.call()
并返回了一个新的观察者Subscriber st
,接着调用了前一级Observable
对应OnSubscriber.call(st)
。
我们再看看OperatorObserveOn.call()
的实现:
public Subscriber<? super T> call(Subscriber<? super T> child) {
...
ObserveOnSubscriber<T> parent = new ObserveOnSubscriber<T>(scheduler, child, delayError, bufferSize);
parent.init();
return parent;
}
OperatorObserveOn.call()
中创建了一个ObserveOnSubscriber
并调用init()
进行了初始化。
static final class ObserveOnSubscriber<T> extends Subscriber<T> implements Action0 {
...
@Override
public void onNext(final T t) {
...
schedule();
}
@Override
public void onCompleted() {
...
schedule();
}
@Override
public void onError(final Throwable e) {
...
schedule();
}
protected void schedule() {
if (counter.getAndIncrement() == 0) {
recursiveScheduler.schedule(this);
}
}
@Override
public void call() {
long missed = 1L;
long currentEmission = emitted;
final Queue<Object> q = this.queue;
final Subscriber<? super T> localChild = this.child;
final NotificationLite<T> localOn = this.on;
for (;;) {
long requestAmount = requested.get();
while (requestAmount != currentEmission) {
boolean done = finished;
Object v = q.poll();
boolean empty = v == null;
if (checkTerminated(done, empty, localChild, q)) {
return;
}
if (empty) {
break;
}
localChild.onNext(localOn.getValue(v));
currentEmission++;
if (currentEmission == limit) {
requestAmount = BackpressureUtils.produced(requested, currentEmission);
request(currentEmission);
currentEmission = 0L;
}
}
if (requestAmount == currentEmission) {
if (checkTerminated(finished, q.isEmpty(), localChild, q)) {
return;
}
}
emitted = currentEmission;
missed = counter.addAndGet(-missed);
if (missed == 0L) {
break;
}
}
}
...
}
ObserveOnSubscriber
继承自Subscriber
,并实现了Action0
接口。我们看到ObserveOnSubscriber
的onNext()
、onCompleted()
、onError()
都有个schedule()
,这个方法就是我们线程调度的关键;通过schedule()
将新观察者ObserveOnSubscriber
发送给subscriberOne
的所有事件都切换到了recursiveScheduler
所对应的线程,简单的说就是把subscriberOne
的onNext()
、onCompleted()
、onError()
方法丢到了recursiveScheduler
对应的线程中来执行。
那么schedule()
又是如何做到这一点的呢?他内部调用了recursiveScheduler.schedule(this)
,recursiveScheduler
其实就是一个Worker
,和我们在介绍subscribeOn()
时提到的worker
一样,执行schedule()
实际上最终是创建了一个runable
,然后把这个runnable
丢到了特定的线程池中去执行。在runnable
的run()
方法中调用了ObserveOnSubscriber.call()
,看上面的代码大家就会发现在call()
方法中最终调用了subscriberOne
的onNext()
、onCompleted()
、onError()
方法。这便是它实现线程切换的原理。
好了,我们最后再看看示例C对应的执行流程图,帮助大家加深理解。
总结
这一章以执行流程、操作符实现以及线程调度三个方面为切入点剖析了RxJava源码。下一章将站在更宏观的角度来分析整个RxJava的框架结构、设计思想等等。敬请期待~~ :)
如果你喜欢我的文章,就关注下我的知乎专栏或者在 GitHub 上添个 Star 吧!
RxJava系列6(从微观角度解读RxJava源码)的更多相关文章
- RxJava系列番外篇:一个RxJava解决复杂业务逻辑的案例
之前写过一系列RxJava的文章,也承诺过会尽快有RxJava2的介绍.无奈实际项目中还未真正的使用RxJava2,不敢妄动笔墨.所以这次还是给大家分享一个使用RxJava1解决问题的案例,希望对大家 ...
- 给jdk写注释系列之jdk1.6容器(6)-HashSet源码解析&Map迭代器
今天的主角是HashSet,Set是什么东东,当然也是一种java容器了. 现在再看到Hash心底里有没有会心一笑呢,这里不再赘述hash的概念原理等一大堆东西了(不懂得需要先回去看下Has ...
- 从面试角度分析LinkedList源码
注:本系列文章中用到的jdk版本均为java8 LinkedList类图如下: LinkedList底层是由双向链表实现的.链表好比火车,每节车厢包含了车厢和连接下一节车厢的连接点.而双向链表的每个节 ...
- Java并发包源码学习系列:阻塞队列实现之PriorityBlockingQueue源码解析
目录 PriorityBlockingQueue概述 类图结构及重要字段 什么是二叉堆 堆的基本操作 向上调整void up(int u) 向下调整void down(int u) 构造器 扩容方法t ...
- Java并发包源码学习系列:阻塞队列实现之SynchronousQueue源码解析
目录 SynchronousQueue概述 使用案例 类图结构 put与take方法 void put(E e) E take() Transfer 公平模式TransferQueue QNode t ...
- 给jdk写注释系列之jdk1.6容器(7)-TreeMap源码解析
TreeMap是基于红黑树结构实现的一种Map,要分析TreeMap的实现首先就要对红黑树有所了解. 要了解什么是红黑树,就要了解它的存在主要是为了解决什么问题,对比其他数据结构比如数组,链 ...
- 给jdk写注释系列之jdk1.6容器(5)-LinkedHashMap源码解析
前面分析了HashMap的实现,我们知道其底层数据存储是一个hash表(数组+单向链表).接下来我们看一下另一个LinkedHashMap,它是HashMap的一个子类,他在HashMap的基础上维持 ...
- 给jdk写注释系列之jdk1.6容器(4)-HashMap源码解析
前面了解了jdk容器中的两种List,回忆一下怎么从list中取值(也就是做查询),是通过index索引位置对不对,由于存入list的元素时安装插入顺序存储的,所以index索引也就是插入的次序. M ...
- 入口开始,解读Vue源码(一)-- 造物创世
Why? 网上现有的Vue源码解析文章一搜一大批,但是为什么我还要去做这样的事情呢?因为觉得纸上得来终觉浅,绝知此事要躬行. 然后平时的项目也主要是Vue,在使用Vue的过程中,也对其一些约定产生了一 ...
随机推荐
- python 中的 args,*args,**kwargs的区别
一.*args的使用方法 *args 用来将参数打包成tuple给函数体调用 例子一:def function(*args): print(args, type(args))function ...
- 数字不断递增 可控制js
(function($){ $.fn.numberRock=function(options){ var defaults={ speed:, count: }; var opts=$.extend( ...
- 面向对象写的简单的colors rain
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> < ...
- three.js 实现全景以及优化(1)
实现一个三维全景; 然后思考优化问题; 于是我问了下webgl技术交流群朋友有啥解决方案; 对于krpano.js 的了解,只是知道百度全景用了这个技术; 最后还是选择了群友给出的three.js ...
- 【Docker】Docker概述
[Docker] Docker可以说是近几年非常热门的技术之一了.不管是别人敦促我还是从自己的想法来说,都觉得Docker这玩意儿肯定是要好好学习一下的,无奈没啥时间专门播出来给Docker,一直以来 ...
- 企业必会技能 tomcat
企业必会技能 tomcat tomcat 一.什么是Tomcat? Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项 ...
- 源码实现 --> strcpy
拷贝字符串到目标字符串 函数 char *strcpy(char *strDestination, const char *strSource); 复制源串strSource到目标串strDestin ...
- ava集合---HashSet的源码分析
一.HasnSet概述 Hashset实现set接口,由哈希表(实际上是一个HashMap实例)支持.它不保证set的迭代顺序.特别是它不保证该顺序恒久不变.此类允许使用Null元素 一.HasnSe ...
- Web安全概述
互联网刚开始是安全的,但是伴随着黑客(Hacker)的诞生,互联网变得越来越不安全.任何一个事情都有两面性,黑客也有好有坏,好的黑客叫白帽子,坏的黑客叫黑帽子.与此同时,随着Web技术发展越来越成熟, ...
- JavaEE Servlet 核心方法及生命周期
做JavaWeb开发,免不了要和Servlet打交道.Servlet是Sun(Oracle)官方定义的一个Web开发规范,所有Servlet开发都必须遵守.自己以前也没有从头做过Web开发,所以这方面 ...