永仁县建设工程信息网站,虹口专业网站建设公司,个人开公司需要什么条件,新乡手机网站建设服务前言 #x1f34a;作者简介#xff1a; 不肯过江东丶#xff0c;一个来自二线城市的程序员#xff0c;致力于用“猥琐”办法解决繁琐问题#xff0c;让复杂的问题变得通俗易懂。 #x1f34a;支持作者#xff1a; 点赞#x1f44d;、关注#x1f496;、留言#x1f4…前言 作者简介 不肯过江东丶一个来自二线城市的程序员致力于用“猥琐”办法解决繁琐问题让复杂的问题变得通俗易懂。 支持作者 点赞、关注、留言~ 相信各位小伙伴对 Stream 都不陌生它是 Java 8 及以后版本中引入的一个新特性用于处理集合数据。Stream 是对集合Collection对象功能的增强与 Lambda 表达式结合可以提高编程效率、间接性和程序可读性。Stream API 中为我们提供了很多高效且易用的方法大聪明的好朋友 —— 大明白就对这些方法情有独钟但是就在前几天却因为他在项目中使用了 Stream.parallel() 而引发了一个小小的意外情况… … 这里卖个关子~ 在说大明白引发的意外情况之前我们先来一起看看什么是Stream.parallel() Stream.parallel()
Stream.parallel() 方法用于将流操作转换为并行操作以便在多个线程上并行执行。并行流是一种可以同时在多个线程上执行操作的流它将流的元素分割成多个子集每个子集在不同的线程上独立处理最后将结果合并。使用 parallel() 方法可以轻松开启并行流处理模式无需显式管理线程和同步。
ListInteger numbers ...; // 假设这里有一个包含大量正整数的List集合numbers.stream() // 创建顺序流.parallel() // 转换为并行流.filter(n - n % 2 0) // 并行流操作 - 过滤List集合中的偶数.map(n - n * 2) // 并行流操作 - 将过滤出来的偶数×2.forEach(System.out::println); // 并行流操作 - 打印结果在上面的示例中parallel() 方法将顺序流转换为并行流后续的 filter()、map() 和 forEach() 操作将在多个线程上并行执行从而加速数据处理。我们下面再看看它的底层原理 当调用 Stream.parallel() 方法时它实际上会返回一个新的并行流对象这个流对象可以在多个线程上并行执行流操作。下面是 Stream.parallel() 方法的大致工作原理① 并行流的划分和分治当我们对并行流进行操作时Java 会使用 Fork/Join 框架将数据划分成多个小任务并将这些小任务分配给多个线程来并行执行。这个过程涉及到递归地将大任务分解为小任务直到小任务足够简单可以直接求解。 ② 工作窃取Work StealingFork/Join 框架采用工作窃取算法来实现任务的调度和执行。在工作窃取的过程中空闲的线程会主动去其他线程的任务队列中窃取任务执行。这种方式能够充分利用线程资源提高并行处理的效率。 ③合并结果在并行流的操作中各个线程会并行地对数据进行处理最后需要将各个线程的处理结果进行合并得到最终的结果。这一过程涉及到结果的收集和合并确保最终的结果是完整且正确的。 这里我们又引申出了一个新的概念 —— Fork/Join 框架。Fork/Join 框架是 Java 7 中引入的用于支持并行计算的框架是一种并行计算模式用于解决可以被分解成更小的可并行任务的问题。该模式包含两个关键操作Fork分解和Join合并。在 Fork/Join 模式中原始问题被递归地分解为更小的子问题直到达到可以并行解决的最小单位。这个过程被称为 Fork。每个子问题可以独立地在不同的处理器上执行并行地求解部分问题。 一旦所有的子问题都被解决就会进行 Join 操作。Join 操作将所有子问题的结果合并为最终的解决方案。这种分解和合并的过程可以视为树形结构其中每个节点代表一个子问题。
Fork/Join 模式最适用于可以自然地分解为多个独立子问题的计算密集型任务。它适用于多核处理器或并行计算环境其中可以充分利用并行性。Java 平台提供了 Fork/Join 框架用于实现该模式。它包括了一个线程池ForkJoinPool 和 任务ForkJoinTask 的概念。任务可以是可分解的子问题也可以是执行最终计算的任务。通过 ForkJoinPool可以将任务提交给线程池执行自动实现任务的分解和合并过程。Fork/Join 模式的优点在于它能够充分利用多核处理器的并行性提高计算效率。 在这里我们就先对 Fork/Join 框架做一个简单的介绍后续大聪明会单独出一篇博客对 Fork/Join 框架进行详细的介绍。 咱们言归正传有些小伙伴看到“线程池ForkJoinPool”的时候可能就已经猜测到大明白遇倒的意外情况和线程有关系了。Stream.parallel() 并行流默认使用的是 ForkJoinPool.commonPool() 作为线程池该线程池默认最大线程数就是 CPU 核数。正是因为大明白对并行流操作的原理不清楚他在没有配置线程池的情况下通过并行流做了数据库的大量批量更新操作于是最大线程数只有 CPU 核数最终导致在批量更新的时候出现了线程阻塞的情况从而出现了这个小小的意外。 通过这件事应该也可以给各位小伙伴提个醒在实际使用时需要慎重考虑并行化带来的影响并确保线程安全性和并发性。 ① 线程安全并行流并不能保证线程安全性因此如果流中的元素是共享资源或操作本身不是线程安全的你需要确保正确同步或使用线程安全的数据结构。 ② 资源消耗并行流默认使用的线程池大小可能与机器的实际物理核心数相适应但也可能与其他并发任务争夺系统资源。 ③ 结果一致性并行流并不保证执行的顺序性也就是说如果流操作的结果依赖于元素的处理顺序则不应该使用并行流。 ④ 事务处理在涉及到事务操作时通常需要避免在并行流中直接处理如上述例子所示应当将事务边界放在单独的服务方法内确保每个线程内的事务独立完成。 小结
本人经验有限有些地方可能讲的没有特别到位如果您在阅读的时候想到了什么问题欢迎在评论区留言我们后续再一一探讨 希望各位小伙伴动动自己可爱的小手来一波点赞关注 (✿◡‿◡) 让更多小伙伴看到这篇文章~ 蟹蟹呦(●’◡’●) 如果文章中有错误欢迎大家留言指正若您有更好、更独到的理解欢迎您在留言区留下您的宝贵想法。 你在被打击时记起你的珍贵抵抗恶意 你在迷茫时坚信你的珍贵抛开蜚语 爱你所爱 行你所行 听从你心 无问东西