其中有一篇博客写的很精彩戳这里,这个非常简洁
还有一篇精彩博文戳这里,这个解释的非常通透
一、背景
无论是java8的CompletableFuture还是RxJava都是基于观察者模式的。只不过Rxjava更强大,有更好的错误处理、中断机制、完成状态
二、创建
- Observable ( 被观察者 ) / Observer ( 观察者 )
- Flowable (被观察者)/ Subscriber (观察者) 【支持回压】
package com.hfview;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import lombok.extern.slf4j.Slf4j;
/**
* 观察者和被观察者创建
*
* @author: zhw
* @since: 2019/3/15 09:36
*/
@Slf4j
public class RxJavaDemo1 {
public static void main(String[] args) {
//创建被观察者---方式1
Observable<String> switcher1 = Observable.create(emitter->{
log.debug("Observable emit 1");
emitter.onNext("1");
log.debug("Observable emit 2");
emitter.onNext("2");
log.debug("Observable emit 3");
emitter.onNext("3");
log.debug("Observable emit 4");
emitter.onNext("4");
log.debug("Observable emit onComplete ");
emitter.onComplete();
});
//创建被观察者---方式2
//Observable<String> switcher2 = Observable.just("on","off","on","on");
//创建被观察者---方式3
//String [] kk={"On","Off","On","On"};
//Observable<String> switcher3 =Observable.fromArray(kk);
//创建观察者
switcher1.subscribe(new Observer<String>() {
private Disposable disposable;
@Override
public void onSubscribe(Disposable d) {
log.debug(" 观察者onSubscribe");
disposable = d;
}
@Override
public void onNext(String s) {
log.debug(" 观察者onNext:"+s);
if(s.equals("2")){
disposable.dispose();
}
}
@Override
public void onError(Throwable e) {
log.error(" 观察者onError",e);
}
@Override
public void onComplete() {
log.info(" 观察者onComplete");
}
});
}
}
- 第一种方式是最基本的,其实后面也是基于它的
- just方式
- fromArray方式
1.1 没有观察者,被观察者是不会生产事件的
假如没有 switcher1.subscribe() 这个操作,观察者不会调用各种释放Next
注意这里有个误解,应该是观察者订阅被观察者,但是为了链式调用的方便,就搞成被观察者订阅观察者了。
1.2 Disposable 方式
如果在观察者onNext方法中调用Disposable 的dispose方法,那么就可以终止获取,但是被观察者仍然继续生产,只是这个观察者不接受了
比如上面观察者中onNext方法只会打印到 观察者onNext:1 观察者onNext:2 剩下的却不打印了。
1.3 观察者onError
如果观察者在onNext中发生异常,那么会在onError自动捕获改异常
二、数据转换处理和线程切换
package com.hfview;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CountDownLatch;
/**
* 数据转换和线程切换
*
* @author: zhw
* @since: 2019/3/15 09:36
*/
@Slf4j
public class RxJavaDemo2 {
public static void main(String[] args) throws Exception{
CountDownLatch countDownLatch = new CountDownLatch(1);
long start = System.currentTimeMillis();
//创建被观察者---方式2
Observable
.just("11011","21011","31011","41011")
//.subscribeOn(Schedulers.newThread())//被观察者线程切换
//.observeOn(Schedulers.io())
.map(s->{
log.debug("map操作当前线程为:"+Thread.currentThread().getName());
return convert(s);//转换功能
})
/*.flatMap(new Function<String, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(String s) throws Exception {
return Observable.fromArray(s.split("0"));
}
})*/
.observeOn(Schedulers.computation())
.subscribe(new Observer<String>() {
private Disposable disposable;
@Override
public void onSubscribe(Disposable d) {
log.debug(" 观察者调用onSubscribe:"+Thread.currentThread().getName());
disposable = d;
}
@Override
public void onNext(String s) {
sleep(2000);
log.debug(" 观察者接受数据onNext:"+s+" "+Thread.currentThread().getName());
}
@Override
public void onError(Throwable e) {
log.error(" 观察者调用onError"+Thread.currentThread().getName(),e);
}
@Override
public void onComplete() {
log.info(" 观察者调用onComplete"+Thread.currentThread().getName());
countDownLatch.countDown();
}
});
countDownLatch.await();
long end = System.currentTimeMillis();
log.debug("主线程结束了,耗时:"+(end-start));
}
/**
* 模拟耗时操作
* @param s
* @return
*/
public static String convert(String s){
//sleep(2000);
return s+"1";
}
public static void sleep(int n){
try {
Thread.sleep(n);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
如果清楚java中Stream中的流处理,那么这里他它差不多
2.1 Map
public final <R> Observable<R> map(Function<? super T, ? extends R> mapper)
在函数式编成中也有这个接口Function,他基本就是负责转换,他需要一个入参? super T 和一个出参 ? extends R
.map(s->{
log.debug("map操作当前线程为:"+Thread.currentThread().getName());
return convert(s);//转换功能
})
public static String convert(String s){
return s+"1";
}
比如上面就是完成将当前字符串+“1”。
2.2 filter
public final Observable<T> filter(Predicate<? super T> predicate);
和函数式接口Predicate一样一个入参,然后返回boolean。true就保留,false就剔除
2.3 线程切换
- 简单地说,subscribeOn() 指定的就是发射事件的线程,observerOn 指定的就是订阅者接收事件的线程。
- 多次指定发射事件的线程只有第一次指定的有效,也就是说多次调用 subscribeOn() 只有第一次的有效,其余的会被忽略。
- 但多次指定订阅者接收线程是可以的,也就是说每调用一次 observerOn(),下游的线程就会切换一次。
关于Schedulers的解释
三、支持回压的模式
3.1 回压
回压或者背压:主要是处理如果被观察者产生时间过快,而观察者来不及处理,导致堆积,导致OOM的事情。
下面是一个例子:
package com.hfview;
import io.reactivex.Flowable;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import java.util.concurrent.CountDownLatch;
/**
* 支持回压的Flowable
*
* @author: zhw
* @since: 2019/3/15 09:36
*/
@Slf4j
public class RxJavaDemo3 {
public static void main(String[] args) throws Exception{
CountDownLatch countDownLatch = new CountDownLatch(1);
long start = System.currentTimeMillis();
final int length = 100000;
String[] arr = new String[length];
for(int i=0;i<length;i++){
arr[i] = (i+1)+"";
}
//创建被观察者---方式2
Flowable.fromArray(arr)
.subscribe(new Subscriber<String>() {
private Subscription subscription;
private int count = 0;
@Override
public void onSubscribe(Subscription s) {
log.debug(" 观察者调用onSubscribe"+Thread.currentThread().getName());
subscription = s;
s.request(10);
}
@Override
public void onNext(String s) {
count++;
//sleep(200);
log.debug(" 观察者接受数据onNext:"+s+" "+Thread.currentThread().getName());
if(count!=0&&count%10==0){
log.debug("观察者再次请求数据10条,当前已经处理了:"+count+"条");
subscription.request(10);
}
}
@Override
public void onError(Throwable e) {
log.error(" 观察者调用onError"+Thread.currentThread().getName(),e);
}
@Override
public void onComplete() {
log.info(" 观察者调用onComplete"+Thread.currentThread().getName());
countDownLatch.countDown();
}
});
countDownLatch.await();
long end = System.currentTimeMillis();
log.debug("主线程结束了,耗时:"+(end-start));
}
/**
* 模拟耗时操作
* @param s
* @return
*/
public static String convert(String s){
return s+"1";
}
public static void sleep(int n){
try {
Thread.sleep(n);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
用法基本和Observable。
区别:
- 观察者onSubscribe中会传递一个类Subscription,他有两个方法
public void request(long n)
和public void cancel()
,意思也很明显,调用request(10),意思我只需要10个事件处理,被观察者收到命令后就产生10个。 cancel就是取消。
四、一个简单例子
package com.hfview;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
/**
* //TODO 写注释
*
* @author: zhw
* @since: 2019/3/15 15:54
*/
@Slf4j
public class RxJavaDemo4 {
public static void main(String[] args) throws Exception{
long start = System.currentTimeMillis();
CountDownLatch countDownLatch = new CountDownLatch(1);
Observable observable1 = Observable.fromCallable(new Callable<String>() {
@Override
public String call() throws Exception {
log.debug("被观察者生成字符串1");
sleep(3000);
return "1";
}
}).subscribeOn(Schedulers.newThread());
Observable observable2 = Observable.fromCallable(new Callable<String>() {
@Override
public String call() throws Exception {
log.debug("被观察者生成字符串2");
sleep(3000);
return "2";
}
}).subscribeOn(Schedulers.newThread());;
Observable observable3 = Observable.fromCallable(new Callable<String>() {
@Override
public String call() throws Exception {
log.debug("被观察者生成字符串3");
sleep(3000);
return "3";
}
}).subscribeOn(Schedulers.newThread());;
//Observable<String> unionObservable = observable1.concatWith(observable2).concatWith(observable3);
Observable<String> unionObservable = observable1.mergeWith(observable2).mergeWith(observable3);
unionObservable
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
log.debug(" 观察者获取数据:"+s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
countDownLatch.countDown();
}
});
countDownLatch.await();
long end = System.currentTimeMillis();
log.debug("主线程结束了,耗时:"+(end-start));
}
public static void sleep(int n){
try {
Thread.sleep(n);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
一共三个事件各自需要3S,现在使用响应式编成,最后只需要3S就完成操作