范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

学习Java8StreamApi(5)Stream周边及其他

  Stream API
  经过前面 4 篇内容的学习,我们已经掌握了 Stream 大部分的知识,本节我们针对之前 Stream 未涉及的内容及周边知识点做个补充。Fork/Join 框架
  fork/join 框架是 Java 7 中引入的新特性 ,它是一个工具,通过 「 分而治之 」 的方法尝试将所有可用的处理器内核使用起来帮助加速并行处理。
  在实际使用过程中,这种 「 分而治之 」的方法意味着框架首先要 fork ,递归地将任务分解为较小的独立子任务,直到它们足够简单以便异步执行。然后,join 部分开始工作,将所有子任务的结果递归地连接成单个结果,或者在返回 void 的任务的情况下,程序只是等待每个子任务执行完毕。
  为了提供有效的并行执行,fork/join 框架使用了一个名为 ForkJoinPool 的线程池,用于管理 ForkJoinWorkerThread 类型的工作线程。Fork/Join 优点
  Fork/Join 架构使用了一种名为工作窃取( work-stealing )算法来平衡线程的工作负载。
  简单来说,工作窃取算法就是空闲的线程试图从繁忙线程的队列中窃取工作。
  默认情况下,每个工作线程从其自己的双端队列中获取任务。但如果自己的双端队列中的任务已经执行完毕,双端队列为空时,工作线程就会从另一个忙线程的双端队列尾部或全局入口队列中获取任务,因为这是最大概率可能找到工作的地方。
  这种方法最大限度地减少了线程竞争任务的可能性。它还减少了工作线程寻找任务的次数,因为它首先在最大可用的工作块上工作。Fork/Join 使用
  ForkJoinTask 是 ForkJoinPool 线程之中执行的任务的基本类型。我们日常使用时,一般不直接使用 ForkJoinTask ,而是扩展它的两个子类中的任意一个任务不返回结果 ( 返回 void ) 的 RecursiveAction返回值的任务的 RecursiveTask
  这两个类都有一个抽象方法 compute() ,用于定义任务的逻辑。
  我们所要做的,就是继承任意一个类,然后实现 compute() 方法,步骤如下:创建一个表示工作总量的对象选择合适的阈值定义分割工作的方法定义执行工作的方法
  如下是使用 Fork/Join 方式实现的1至1000006587的 Fork/Join 方式累加,我们和单线程的循环累加做了下对比,在 Intel i5-4460 的 PC 机器下,单线程执行使用了 650 ms,使用了 Fork/Join 方式执行 210 ms,优化效果挺明显。public class NumberAddTask extends RecursiveTask {      private static final int THRESHOLD = 10_0000;     private final int begin;     private final int end;      public NumberAddTask(int begin, int end) {         super();         this.begin = begin;         this.end = end;     }      @Override     protected Long compute() {         if (end - begin <= THRESHOLD) {             long sum = 0;             for(int i = begin; i <= end; i++) {                 sum += i;             }             return sum;         }         int mid = (begin + end) /2;         NumberAddTask t1 = new NumberAddTask(begin, mid);         NumberAddTask t2 = new NumberAddTask(mid + 1,  end);         ForkJoinTask.invokeAll(t1, t2);         return t1.join() + t2.join();     } }  // 1至1000006587的Fork/Join方式累加 @Test public void testAddForkJoin() {     long begin = System.currentTimeMillis();     int n = 10_0000_6587;     ForkJoinPool pool = ForkJoinPool.commonPool();     log.info("1 + 2 + ... {} = {}", n, pool.invoke(new NumberAddTask(1, n)));     long end = System.currentTimeMillis();     log.info("ForkJoin方式执行时间:{}ms", end - begin); }  // 1至1000006587的单线程累加 @Test public void testAddFunction() {     long begin = System.currentTimeMillis();     int n = 10_0000_6587;     long sum = 0;     for(int i = 1; i <= n; i++ ) {         sum += i;     }     log.info("1 + 2 + ... {} = {}", n, sum);     long end = System.currentTimeMillis();     log.info("函数方式执行时间:{}ms", end - begin); } Fork/Join 使用场景
  我使用 Java 8 官方 Api 中 RecursiveTask 的示例,创建了一个计算斐波那契数列的 Fork/Join 实现,虽然官方也提到了这是愚蠢的实现斐波那契数列方法,甚至效果还不如单线程的递归计算,但是这也说明了 Fork/Join 并非万能的。@Test public void testForkJoin() {     // 执行f(40) = 102334155使用3411ms     // 执行f(80) 2个多小时,无法计算出结果     long begin = System.currentTimeMillis();     int n = 40;     ForkJoinPool pool = ForkJoinPool.commonPool();     log.info("ForkJoinPool初始化时间:{}ms", System.currentTimeMillis() - begin);     log.info("斐波那契数列f({}) = {}", n, pool.invoke(new FibonacciTask(n)));     long end = System.currentTimeMillis();     log.info("ForkJoin方式执行时间:{}ms", end - begin); }  // 不用递归计算斐波那契数列反而更快 @Test public void testFibonacci() {     // 执行f(50000) 使用 110ms     // 输出 f(50000) = 17438开头的10450位长的整数     long begin = System.currentTimeMillis();     int n = 50000;     log.info("斐波那契数列f({}) = {}", n, FibonacciUtil.fibonacci(n));     long end = System.currentTimeMillis();     log.info("函数方式执行时间:{}ms", end - begin); }
  以上代码见 StreamOtherTest 。
  Fork/Join 最大的优点是提供了工作窃取算法,可以在多核CPU处理器上加速并行处理,他并非多线程开发替代品。
  那么他们之间有什么区别呢?
  Fork/Join框架是从jdk7中新特性,它同ThreadPoolExecutor一样,也实现了Executor和ExecutorService接口。它使用了一个无限队列来保存需要执行的任务,而线程的数量则是通过构造函数传入,如果没有向构造函数中传入希望的线程数量,那么当前计算机可用的CPU数量会被设置为线程数量作为默认值。
  ForkJoinPool主要用来使用分治法(Divide-and-Conquer Algorithm)来解决问题。典型的应用比如快速排序算法。这里的要点在于,ForkJoinPool需要使用相对少的线程来处理大量的任务。比如要对1000万个数据进行排序,那么会将这个任务分割成两个500万的排序任务和一个针对这两组500万数据的合并任务。以此类推,对于500万的数据也会做出同样的分割处理,到最后会设置一个阈值来规定当数据规模到多少时,停止这样的分割处理。比如,当元素的数量小于10时,会停止分割,转而使用插入排序对它们进行排序。那么到最后,所有的任务加起来会有大概2000000+个。问题的关键在于,对于一个任务而言,只有当它所有的子任务完成之后,它才能够被执行。
  所以当使用ThreadPoolExecutor时,使用分治法会存在问题,因为ThreadPoolExecutor中的线程无法像任务队列中再添加一个任务并且在等待该任务完成之后再继续执行。而使用ForkJoinPool时,就能够让其中的线程创建新的任务,并挂起当前的任务,此时线程就能够从队列中选择子任务执行。
  那么使用ThreadPoolExecutor或者ForkJoinPool,会有什么差异呢?
  首先,使用ForkJoinPool能够使用数量有限的线程来完成非常多的具有父子关系的任务,比如使用4个线程来完成超过200万个任务。但是,使用ThreadPoolExecutor时,是不可能完成的,因为ThreadPoolExecutor中的Thread无法选择优先执行子任务,需要完成200万个具有父子关系的任务时,也需要200万个线程,显然这是不可行的。
  在实践中,ThreadPoolExecutor通常用于同时(并行)处理许多独立请求(又称为事务),Fork/Join通常用于加速一项连贯的工作任务。parallelStream 并行化
  parallelStream 其实就是一个并行执行的流.它通过默认的 ForkJoinPool ,可以提高你的多线程任务的速度。parallelStream 具有并行处理能力,处理的过程会分而治之,也就是将一个大任务切分成多个小任务,这表示每个任务都是一个操作,可以并行处理。parallelStream 的使用
  使用方式:创建时返回并行流:如 Collection.parallelStream()过程中转换为并行流:如 Stream.parallel()如果需要,转换为顺序流:Stream.sequential()// 并行流时,并非按照1,2,3...500的顺序输出 IntStream.range(1, 500).parallel().forEach(System.out::println); parallelStream 的陷阱
  由于 parallelStream 使用的是 ForkJoinPool 中的 commonPool,该方法默认创建程序运行时所在计算机处理器内核数量的线程,当同时存在多个工作并行执行时,ForkJoinPool 中的线程将被消耗完,而当有的worker因为执行耗时操作,将导致其他工作也被阻塞,而此时我们也不清楚哪个任务导致了阻塞。这就是 parallelStream 的陷阱。
  parallelStream 是无法预测的,而且想要正确地使用它有些棘手。几乎任何 parallelStream 的使用都会影响程序中其他部分的性能,而且是一种无法预测的方式。但是在调用stream.parallel() 或者 parallelStream() 时候在我的代码里之前我仍然会重新审视一遍他给我的程序究竟会带来什么问题,他能有多大的提升,是否有使用他的意义。
  那么到底是使用 stream 还是 parallelStream 呢?通过下面3个标准来鉴定
  1. 是否需要并行?
  在回答这个问题之前,你需要弄清楚你要解决的问题是什么,数据量有多大,计算的特点是什么?并不是所有的问题都适合使用并发程序来求解,比如当数据量不大时,顺序执行往往比并行执行更快。毕竟,准备线程池和其它相关资源也是需要时间的。但是,当任务涉及到I/O操作并且任务之间不互相依赖时,那么并行化就是一个不错的选择。通常而言,将这类程序并行化之后,执行速度会提升好几个等级。
  2. 任务之间是否是独立的?是否会引起任何竞态条件?
  如果任务之间是独立的,并且代码中不涉及到对同一个对象的某个状态或者某个变量的更新操作,那么就表明代码是可以被并行化的。
  3. 结果是否取决于任务的调用顺序?
  由于在并行环境中任务的执行顺序是不确定的,因此对于依赖于顺序的任务而言,并行化也许不能给出正确的结果。创建流的其他方式
  我们在第1篇中记录了几种创建流的方式,但还是遗漏了一部分,再此稍作补充。从I/O通道
  方式1:从缓存流中读取为Stream,详见如下代码:final String name = "明玉"; // 从网络上读取文字内容 new BufferedReader(         new InputStreamReader(                 new URL("")                 // new URL("")                         .openStream()))         .lines()         .filter(str -> StrUtil.contains(str, name))         .forEach(System.out::println);
  方式2:从文件系统获取下级路径及文件,详见如下代码:// 获取文件系统的下级路径及其文件 Files.walk(FileSystems.getDefault().getPath("D:\soft"))         .forEach(System.out::println);
  方式3:从文件系统获取文件内容,详见如下代码:Files.lines(FileSystems.getDefault().getPath("D:", "a.txt"))     // .parallel()     .limit(200)     .forEach(System.out::println);
  方式4:读取JarFile内的文件,详见如下代码:new JarFile("D:\J2EE_Tools\repository\org\springframework\spring-core\5.2.6.RELEASE\spring-core-5.2.6.RELEASE.jar")         .stream()         .filter(entry -> StrUtil.contains(entry.getName(), "Method"))         .forEach(System.out::println); 获取随机数字流
  使用类Random的ints、longs、doubles的方法,根据传递不同的参数,可以产生无限数字流、有限数字流、以及指定范围的有限或无限数字流,示例如下:double v = new Random()         .doubles(30, 2, 45)         .peek(System.out::println)         .max()         .getAsDouble(); log.info("一串随机数的最大值为:{}", v); 位向量流
  将BitSet中位向量为真的转换为Stream,示例如下:BitSet bitSet = new BitSet(8); bitSet.set(1); bitSet.set(6); log.info("cardinality值{}", bitSet.cardinality()); bitSet.stream().forEach(System.out::println); 正则分割流
  将字符串按照正则表达式分隔成子串流,示例如下:Pattern.compile(":")         .splitAsStream("boo:and:foo")         .map(String::toUpperCase)         .forEach(System.out::println); Stream 的其他方法转为无序流
  使用 unordered() 方法可将 Stream 随时转为无序流。转换为Spliterator
  使用 spliterator() 方法可将 Stream 转为 Spliterator,Spliterator 介绍请看 https://juejin.im/post/5cf2622de51d4550bf1ae7ff。综合示例
  根据1962年第1届百花奖至2018年第34届百花奖数据,有以下数据,编写代码按照获得最佳男主角的演员次数排名,次数相同的按照参演年份正序排,并打印他所参演的电影。
  根据题目要求,创建 HundredFlowersAwards 实体用来存储上述数据,我们分析题目要求最终需要转换为以演员为主的信息,然后再根据演员的获奖次数及出演年份做排序。 所以创建 ActorInfo 实体,包含 演员姓名和出演电影的信息。出演电影也需创建实体 FilmInfo ,包含 出演年份和电影名称。
  有了如上存储数据实体信息后,代码实现逻辑如下:将百花奖的集合数据转换为 Stream将该数据流转换为Map类型,Map 的 key 为演员名,Map 的 Value 为演员信息对于重复出现的演员,我们需要把电影信息追加到该演员出现的电影列表中对于处理完的 Map 数据,将该 Map 的 values 数据再次转换为 Stream将该 Stream 排序即可。list.stream()     .collect(Collectors.toMap(HundredFlowersAwards::getActorName, ActorInfo::new, ActorInfo::addFilmInfos))     .values()     .stream()     .sorted(new ActorComparator())     .forEach(System.out::println);
  本节代码见 StreamOtherTest 。
  经过几天的学习和总结,以上就是 Java Stream Api 的全部内容了。从开始认识 Stream Api,我们逐渐了解了使用 Stream Api 的流程:创建 Stream 、中间操作、终端操作。 我们对创建 Stream 、中间操作、终端操作的各个 api 方法进行了介绍及案例演示,之后我们还单独抽出一节讲解了 Collector 接口的实现及使用。 上述内容虽然文字不多,大部分都在代码中给出了演示,希望大家能下载下来代码并运行,以加深印象。
  以上是前传部分的学习内容了,接下来我们将进入到 Reactor 部分的学习。
  源码下载:https://gitee.com/liuchuang.com/spring-web-flux-study-note

海天味业回应点蓝字关注,不迷路来源海天味业微博9月30日晚间,海天味业官方微博发布一则声明,对近期产品添加剂争议进行回应。在声明中,海天味业表示,海天所有产品都严格按照食品安全法生产,并且随时怎么样才能忘掉情人,你们看我还有救吗?有人说,忘记一个人最好的方式就是不打扰,不联系,寻找下一份感情,时间可以让你忘掉一切,可是真正爱过的人,能轻易的做到吗?也有人说想要忘掉一个人,不是拉黑删除,不是发毒誓。不要刻意想赵丽颖的9帧美照,每张皆是珍藏款1。清欢共,紫陌红尘相逢望苍穹,掠眼繁华谁懂。2。成功需要成本,时间也是一种成本,对时间的珍惜就是对成本的节约。3。你是心你是肝你是我的四分之三。我做不得什么旷世的奇才,我只愿做你2022年国庆节要来了,特别祝福语请先收藏起来1摒弃忙碌的疲惫,打开美好的回味,沐浴阳光的明媚,让温柔的风尽情吹,摘下秋果的累累,笼罩喜庆的祥瑞,享受美酒的沉醉。国庆佳节,愿你心情是最美!2十一到,记住几个多与少。多饮水,少饮董文华饭桌上高歌引欢呼!脸部圆润双下巴突出,桌上千元名酒抢眼近日,有网友在社交平台上晒出一则董文华与好友聚餐的视频,她在席间高歌活跃气氛,引起一众网友的关注。视频中董文华身穿棕色外套,一头利落短发,脖间带着一串珠子,脸颊涂粉打扮精致,只见她崇明这座庄园民宿里竟然还藏着个小公园穿梭幽静茂密的杉林,走过临近河流的小径,你永远不知道下一秒会收获什么样的风景。是花境迷人,是竹林幽幽?是湖心小岛,是曲折廊桥?是碧波荡漾,是泳池光影?今天小编要带你去一处庄园民宿,开封龙亭公园一日游龙亭位于开封市城内西北隅,建于六朝(五代时期后梁后晋后汉后周和北宋及金朝)皇宫的遗址之上,以金碧辉煌气势雄伟的龙亭大殿为主,由午门玉带桥嵩呼朝门照壁朝房等清朝万寿宫建筑群组成。充分最美青秋青海化隆软儿梨熟了开栏的话高原入秋,美不胜收。进入秋季,青海大地景致各异,乡村田园收获硕果,农牧民群众喜笑颜开。央广网青海频道即日起推出系列报道最美青秋,展现青海72万平方公里的广阔土地上,不容错过巩固拓展生态保护和环境治理成效青海省湖泊型国家公园建设的探索实践青海湖,位于青藏高原东北部,是我国最大的内陆咸水湖。青海省因青海湖而得名。公主入藏时曾经过这里,留下了动人的传说歌曲在那遥远的地方正是从青海湖出发,风靡海内外。这里也是国家级自然保落叶与秋风的邂逅转眼间,秋天已经进入下半程,大自然中,满眼的绿色,将渐次显露出不同来,有的变黄,有的转红,有的枯萎,有的凋零,大片大片的落叶林换秋日的盛装,在树叶落光前尽显一派秋日迷人的风光。从风一批茶叶公共品牌集中亮相天安门地铁通道昨日,中华合作时报茶周刊全媒体记者在乘坐北京地铁一号线时发现,天安门东西两个地铁站通道展区的LED大屏正在滚动播出辉煌的中国,内容主要是全国各地的国家地理标志产品形象宣传,包括茶叶
俄16艘舰合围日本,诠释瘦死骆驼比马大,购买054或是出路在苏联解体之后,俄罗斯也继承了苏联的绝大部分衣钵,可以看出目前俄罗斯海军所使用的绝大部分主力战舰几乎全部都是苏联时代的武器,尽管继承了苏联时代的衣钵,但是如今的俄罗斯海军也只是瘦死德媒中国若统一,会将台积电据为己有,全球经济将毁于一旦近日,德国媒体德国编辑部网络发表了一篇题为失去台湾,世界经济将毁于一旦的文章,妄图用一些危言耸听的言论来干涉台海局势。文章的核心观点认为,中国若成功统一,会独吞台积电,届时全球经济主持人任鲁豫因病缺席重大晚会,近况曝光引热议,暂离央视1个月近日,网上传出香港回归25周年文艺晚会嘉宾名单,已定下8位主持人,分别是汪明荃曾志伟邓梓峰陈贝儿龙洋尼克买提马凡舒张凯丽等,而我们平时所熟悉的任鲁豫,却消失在名单之中,不少粉丝为之福建号下水,美兰德公司承认美舰过中国台海经济专属区属无害通过文刘澜昌中国第三艘航空母舰福建号下水,美国虽然猜测要到2025年才能形成战斗力,但是也承认,中国海军新航母下水是向整个地区表明中国军方将具备向太平洋更远处投送军力的能力。尤其可从第谈旅游之于美好生活的意义旅游业作为典型的幸福产业和大健康产业,是美好生活的必然组成部分。只要是基于生活导向与人性需求的,其业态创新永无止境。从人类发展稳中向好的长时态看,旅游已然成为现代人们的生活方式学习从乞丐变强盗,乌克兰是否还值得同情?面对勒索,欧洲内部有分歧作为一名国家领导人,并不是每一次出国访问,都是那么令人愉快。而德国总理奥拉夫肖尔茨(OlafScholz)近日与法国总统埃马纽埃尔马克龙(EmmanuelMacron)意大利总理马普京对台湾问题正式表态,将加强中俄合作,美国对中国发出警告作者常有礼阅读指南普京在中俄元首电话中表态,支持中国在台湾问题上的立场,美国挑拨中俄关系失败,竟然气急败坏的威胁中国不要站在历史错误的一边。据央视新闻报道,6月15日中俄两国元首再32022WTT常规挑战赛萨格勒布站,国乒小将向鹏31击败张本智和晋级8强,整场比赛,向鹏发挥的非常出色。客观地讲,其个人实力已经可以比肩世界顶尖高手。世界排名方面,张本智和世界第7共和国第三艘航母福建舰大家好,周末愉快,周末的意思是今天不用讨论那么正经的财报。这个周最振奋人心的消息,莫过于福建舰在6月17日正式下水。说个冷知识,福建是共和国为数不多的迄今为止尚未全境完全统一的省份砸手里了!仅剩12天,亚洲杯举办权仍无人问津,亚足联尴尬了2023年亚洲杯,本来是在我国举办的。为此,北京天津上海重庆成都西安大连青岛厦门和苏州10座城市,按照亚足联的要求新建或翻新了大型体育场。目前,眼看一座座花费巨资建起的体育场拔地而今夏目前最贵转会前十琼阿梅尼8千万欧第1,努涅斯第2哈兰德第3直播吧6月18日讯英超和法甲的转会窗口刚刚开启,西甲德甲和意甲则仍需等待到7月1日,不过许多欧洲豪强已经官宣了多笔重磅引援。德国天空体育盘点了这个夏窗到目前为止最贵的十笔转会,数据