RxJava初探

目录

目录

一、预备知识

1.响应式编程

2.观察者模式(发布订阅模式)

二、RxJava

1.RxJava是什么?

2.RxJava的优缺点

3.基本原理

三、基本操作符

Map

FlatMap

Buffer

Interval

四、应用场景

demo源码

参考文献

相关链接




一、预备知识

1.响应式编程

响应式编程(reactive programming)是一种基于数据流(data stream)和变化传递(propagation of change)的声明式(declarative)的编程范式。

响应式编程常见的各种listener,callback,UI。

2.观察者模式(发布订阅模式)

二、RxJava

1.RxJava是什么?

RxJava是一个遵循观察者设计模式,封装后的异步操作库。

2.RxJava的优缺点

优点:

1.流式处理,代码简洁;

2.功能强大,各种操作符丰富,错误处理;

3.异步调度。

缺点:

1.上手困难,与传统编程方式差异很大;

2.服务端开发多同步操作,应用场景有限,Android编程更广泛。

3.基本原理

RxJava四要素

一个基本使用的例子

    Observable.create((ObservableOnSubscribe<Integer>) e -> {
            e.onNext(1);
            e.onNext(2);
            e.onNext(3);
            e.onComplete();
        }).subscribe(new Observer<>() {
            @Override
            public void onSubscribe(Disposable disposable) {
                System.out.println("onSubscribe...");
            }

            @Override
            public void onNext(Integer integer) {
                System.out.println("onNext..." + integer);
            }

            @Override
            public void onError(Throwable throwable) {
                System.out.println("onError..." + throwable.getMessage());
            }

            @Override
            public void onComplete() {
                System.out.println("onComplete...");
            }
        });

输出:
onSubscribe...
onNext...1
onNext...2
onNext...3
onComplete...

线程转换

subscribeOn(Schedulers.single())  产生事件的线程

observeOn(Schedulers.single())    消费线程

IO

最常见的调度器之一。用于IO相关操作。比如网络请求和文件操作。IO 调度器背后由线程池支撑。无限大小多线程池。

Computation

这个是计算工作默认的调度器,它与I/O操作无关。它也是许多RxJava方法的默认调度器:buffer(),debounce(),delay(),interval(),sample(),skip()

Single

此款调度器非常简单,由一个线程支持。所以无论有多少个observables,都将只运行在这个线程上。也可将其认为是主线程的一个替代

Trampoline

当我们想在当前线程执行一个任务时,并不是立即,我们可以用.trampoline()将它入队。这个调度器将会处理它的队列并且按序运行队列中每一个任务。它是repeat()retry()方法默认的调度器。

Executor Scheduler

更像是一种自定义的IO调度器。我们可以通过制定线程池的大小来创建一个自定义的线程池。适用于observables的数量对于IO调度器太多的场景使用,使用如下:

三、基本操作符

Map

FlatMap

它可以把一个发射器 Observable 通过某种方法转换为多个 Observables,然后再把这些分散的 Observables装进一个单一的发射器 Observable。但有个需要注意的是,flatMap 并不能保证事件的顺序,如果需要保证,需要用到我们下面要讲的 ConcatMap

Observable.create((ObservableOnSubscribe<Integer>) e -> {
            e.onNext(1);
            e.onNext(2);
            e.onNext(3);
        }).flatMap((Function<Integer, ObservableSource<String>>) integer -> {
            List<String> list = new ArrayList<>();
            for (int i = 0; i < integer; i++) {
                list.add("I am value " + integer);
            }
            return Observable.fromIterable(list);
        }).subscribe(flatElement -> System.out.println("subscribe-" + flatElement));

输出:
subscribe-I am value 1
subscribe-I am value 2
subscribe-I am value 2
subscribe-I am value 3
subscribe-I am value 3
subscribe-I am value 3

Buffer

buffer 操作符接受两个参数,buffer(count,skip),作用是将 Observable 中的数据按 skip (步长) 分成最大不超过 count 的 buffer ,然后生成一个 Observable

Observable.just(1, 2, 3, 4, 5)
            .buffer(3, 2)
            .subscribe(integers -> {
                System.out.println("buffer size : " + integers.size() + ", buffer value :");
                for (Integer i : integers) {
                    System.out.print(i + ",");
                }
                System.out.println();
            });


输出:
buffer size : 3, buffer value :
1,2,3,
buffer size : 3, buffer value :
3,4,5,
buffer size : 1, buffer value :
5,

Interval

interval 操作符用于间隔时间执行某个操作,其接受三个参数,分别是第一次发送延迟,间隔时间,时间单位。

Observable.interval(0, 1, TimeUnit.SECONDS, Schedulers.trampoline())
            .observeOn(Schedulers.trampoline())
            .subscribe(aLong -> System.out.println("interval :" + aLong + " at " + LocalDateTime.now()));

输出:
interval :0 at 2021-06-06T23:28:52.988059
interval :1 at 2021-06-06T23:28:53.965217
interval :2 at 2021-06-06T23:28:54.964462
interval :3 at 2021-06-06T23:28:55.964698
interval :4 at 2021-06-06T23:28:56.965941
interval :5 at 2021-06-06T23:28:57.964382
interval :6 at 2021-06-06T23:28:58.969673
interval :7 at 2021-06-06T23:28:59.966106

四、应用场景

1.线程切换

@Test
    public void testThreadControl() {
        Function<Integer, Integer> function = integer -> {
            log.info("currentThread: {}, data:{}", Thread.currentThread().getName(), integer);
            return integer;
        };

        Supplier<Integer> supplier = () -> {
            Thread.sleep(3000);
            return 1;
        };

        ExecutorService executor = Executors.newFixedThreadPool(1);
        PublishSubject.fromSupplier(supplier)
                      .subscribeOn(Schedulers.trampoline())//主线程发送数据
                      .map(function)//new 1 线程接收数据
                      .observeOn(Schedulers.single())//切换single 线程接收数据
                      .map(function)//single 线程接收数据
                      .observeOn(Schedulers.from(executor))//自定义线程池
                      .map(function)//自定义线程池 接收数据
                      .subscribe(System.out::println);
    }

日志:
13:57:34.911 [main] INFO RxJavaTest - currentThread: main, data:1
13:57:34.925 [RxSingleScheduler-1] INFO RxJavaTest - currentThread: RxSingleScheduler-1, data:1

13:57:34.929 [pool-2-thread-1] INFO RxJavaTest - currentThread: pool-2-thread-1, data:1
1

2.心跳/指标收集

@SpringBootTest(classes = Application.class)
public class RxJavaTest {

    private Subject<Long> collectPipeline;

    @Before
    public void init() {
        this.collectPipeline = PublishSubject.create();
        this.collectPipeline.observeOn(Schedulers.trampoline()).subscribeOn(Schedulers.trampoline())
                            .buffer(1, TimeUnit.SECONDS, Schedulers.computation(), 5, HashSet::new, false)
                            .filter(CollectionUtils::isNotEmpty).subscribe(this::batchSaveUserLastActiveTime);
    }

    public void emitActiveUserId(Long userId) {
        collectPipeline.onNext(userId);
        System.out.println(String.format("online userId: %s", userId));
    }

    private void batchSaveUserLastActiveTime(Set<Long> idSet) {
        System.out.println(
                String.format("save user last active time, size:%s, ids:%s", idSet.size(), idSet));
    }

    @Test
    public void testBuffer() throws InterruptedException {
        List<Long> idList = Arrays.asList(1000L, 1001L, 1000L, 1002L, 1003L, 1004L, 1005L, 1006L);
        for (Long id : idList) {
            emitActiveUserId(id);
        }
        Thread.sleep(2000);
    }
}


日志:
online userId: 1000
online userId: 1001
online userId: 1000
online userId: 1002
online userId: 1003
save user last active time, size:5, ids:[1000, 1001, 1002, 1003, 1004]
online userId: 1004
online userId: 1005
online userId: 1006
save user last active time, size:2, ids:[1005, 1006]

使用concat和first做缓存

使用timer做定时操作。当有“x秒后执行y操作”类似的需求的时候,想到使用timer

使用interval做周期性操作。当有“每隔xx秒后执行yy操作”类似的需求的时候,想到使用interval

Hystrix使用RxJava简洁的window API来构建metric.

demo源码

demo源码地址

参考文献

rxjava异步框架源码解析

RxJava调度器

相关链接

RxJava国内外文档/库/项目总结

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值