热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:反应式编程Reactor中的多线程

本文由编程笔记#小编为大家整理,主要介绍了反应式编程Reactor中的多线程相关的知识,希望对你有一定的参考价值。在
本文由编程笔记#小编为大家整理,主要介绍了反应式编程Reactor中的多线程相关的知识,希望对你有一定的参考价值。


中,我们对反应式编程有了基本的了解。并顺带了解了Java中反应式编程的最佳时间Reactor。今天我们继续通过Reactor来了解反应式编程,我们今天要说的Reactor中的多线程。










传统的Java多线程







在传统的Java多线程开发场景中,我们通常使用 Executors 工具类来创建线程池,通常是如下几种类型:




  • newCachedThreadPool 创建一个弹性大小的缓存线程池,如果线程池长度超过处理需要,则灵活回收空闲线程。如果没有可回收的线程,则新建线程。


  • newFixedThreadPool 创建一个固定大小的线程池,可控制线程最大并发数,超出的线程会在队列中进行等待。


  • newScheduledThreadPool 创建一个固定大小的线程池,支持定时及周期性的任务执行。


  • newSingleThreadExecutor 创建一个单线程的线程池,它只会用唯一的工作线程来执行任务,保证所有的任务按照指定顺序执行。


  • newWorkStealingPool 创建支持work-stealing(任务窃取,在之前的Go并发模型中有所提到,后续我会专门写文章介绍)的线程池。



可以说传统的 Executors 工具类已经让我们使用线程池变得非常顺手。Reactor则更近一步,提出了更傻瓜式的调度器 Scheduler










Reactor的多线程







Reactor中提供了 Schedulers 类可以创建如下几种线程环境:




  • Schedulers.immediate() 当前线程。


  • Schedulers.single() 对所有的调用者都提供同一个线程来使用,如果想使用独占的线程可以使用 Schedulers.newSingle()


  • Schedulers.elastic() 弹性线程池,根据需要创建一个线程池,重用空闲线程。线程池如果空闲时间过长就会被废弃。对于I/O阻塞的场景较为使用。Schedulers.elastic() 能够给每一个阻塞的任务分配线程,从而不会妨碍其他的任务和资源。


  • Schedulers.paraller() 固定大小线程池,默认创建的大小和CPU个数相同。


  • Schedulets.fromExecutorService(ExecutorService) 自定义线程池,基于自定义的Ex二次投入Service创建Scheduler。



Schedulers类已经预先创建了几种常用的线程池:使用single()elastic()parallel()方法可以分别使用内置的单线程、弹性线程池和固定大小线程池。如果想创建新的线程池,可以使用newSingle()newElastic()newParallel()方法。


我们从上面的描述可以看出,Reactor中的Schedulers和传统的Java多线程有一定的对应关系:




  • Schedulers.single()Schedulers.newSingle()对应Executors.newSingleThreadExecutor()


  • Schedulers.elastic()Schedulers.newElastic()对应Executors.newCachedThreadPool()


  • Schedulers.parallel()Schedulers.newParallel()对应Executors.newFixedThreadPool()



Schedulers提供的以上三种调度器底层都是基于ScheduledExecutorService的,因此都是支持任务定时和周期性执行的;










Reactor中的线程环境切换







和传统的Java多线程编程相比,Reactor提供了一种非常便利的切换线程的方式。也就是publishOnsubscribeOn方法。


Reactor本质上是对数据流的处理,基本模型也是发布-订阅模式。一般来说我们最终调用 subsribe() 方法时,形成了从上到下的数据流(发布端->订阅端)。但是其实还有一条从下到上的订阅流(订阅端->发布端),能够将订阅端的请求从下到上进行反馈。


明白了上面的内容,我们就能够很好理解publishOnsubscribeOn 的区别了, subscribeOn 会借助订阅流从下到上改变源头的线程执行环境。而 publishOn 则会借助数据流从上到下改变后续的执行环境。


我们通过以下的例子来进一步了解一下:





@Test
public void testScheduling() {
    Flux.range(0, 1)
        .log() // 1
        .publishOn(Schedulers.newParallel("myParallel"))
        .log() // 2
        .subscribeOn(Schedulers.newElastic("myElastic"))
        .log() // 3
        .blockLast();
}





  • 1处的log:会打印当前线程是 myElastic-x 


  • 2处的log:会打印当前线程是 myParallel-x 


  • 3处的log:会打印当前线程是 myParallel-x 



通过这个log分析,我们可以得到上面的结论:



  • publishOn会影响链中其后的操作符,比如上面的2和3处的log


  • subscribeOn无论出现在什么位置,都只影响源头的执行环境,比如上面1处的log



并且从我们使用的情况来看,Reactor中的线程切换非常方便。只需要使用 publishOnsubscribeOn 就可以定制我们的线程环境。










总结






Reactor中的多线程本质上和传统Java编程中的多线程没有什么区别,但是增加了很多语法糖,方便了在反应式编程中的多线程使用。并且在Reactor中做多线程环境的切换也是非常方便的,这个和我们在中提到的反应式编程更多的是定制流程,一旦我们的流程定制好了,那么最终数据就会按照我们期待的方式像流水一样流到最终位置。








推荐阅读
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 基于事件驱动的并发编程及其消息通信机制的同步与异步、阻塞与非阻塞、IO模型的分类
    本文介绍了基于事件驱动的并发编程中的消息通信机制,包括同步和异步的概念及其区别,阻塞和非阻塞的状态,以及IO模型的分类。同步阻塞IO、同步非阻塞IO、异步阻塞IO和异步非阻塞IO等不同的IO模型被详细解释。这些概念和模型对于理解并发编程中的消息通信和IO操作具有重要意义。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 本文介绍了Java虚拟机中的垃圾收集器,包括年轻代收集器Serial收集器、ParNew收集器、Parallel Scavenge收集器,以及老年代收集器Serial Old收集器、Parallel Old收集器和CMS收集器。对每种收集器的算法和特点进行了详细解析,希望对读者有参考价值。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
  • Spring Batch中多线程配置及实现例子
    本文介绍了在Spring Batch中开启多线程的配置方法,包括设置线程数目和使用线程池。通过一个示例演示了如何实现多线程从数据库读取数据并输出。同时提到了在多线程情况下需要考虑Reader的线程安全问题,并提供了解决方法。 ... [详细]
  • Spring框架《一》简介
    Spring框架《一》1.Spring概述1.1简介1.2Spring模板二、IOC容器和Bean1.IOC和DI简介2.三种通过类型获取bean3.给bean的属性赋值3.1依赖 ... [详细]
author-avatar
YYCC77777
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有