Java多线程+分治求和,太牛了

shigen坚持更新文章的博客写手,擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长,分享认知,留住感动。
个人IP:shigen

最近的一个面试,shigen简直被吊打,简历上写了熟悉高并发。完了面试官不按照套路出牌,我说了我用了countdownLanch,他问forkjoin了解吗?LRU怎么设计……一脸懵,尴尬的直接抠脚。

赶紧花时间研究了,顺便看了一下线程池,看到了这样一个经典的案例:

求1-10000_0000的和。

没错,别眼花,是1-1个亿个数字的和。别告诉我,直接循环相加,那就回家等通知吧。

好的,前提就聊到这。看看我这一段炫酷的代码:

代码案例

天啊,task+递归,和着在线程池不断的玩呗。


一看这种分而治之,像极了传说中的二分法,经典的分治思想。等等,我咋这么熟悉!

没错,经典的归并排序,就是这样子的!花了一小时,把这个算法用Java写出来了。shigen之前可是用的python写算法。

java版归并排序

public class MergeSortDemo {// 归并排序static void mergeSort(int[] arr, int left, int right) {if (left < right) {int mid = (left + right) / 2;// 简直直接midmergeSort(arr, left, mid);mergeSort(arr, mid + 1, right);merge(arr, left, mid, right);}}private static void print(int[] arr) {for (int i = 0; i < arr.length; i++) {System.out.print(arr[i] + " ");}System.out.println();}private static void merge(int[] arr, int left, int mid, int right) {// 构建一个临时数组暂存arr[left, right]之间有序的元素int[] temp = new int[right - left + 1];int i = left, j = mid + 1, k = 0;// while的临界条件需注意,此时分段有序数组合并// [1,2,3] + [1,3,4,5,6] mid = 4while (i <= mid && j <= right) {if (arr[i] < arr[j]) {temp[k++] = arr[i++];} else {temp[k++] = arr[j++];}}// 剩下的元素直接追加即可,两个while只会走一个while (i <= mid) {temp[k++] = arr[i++];}while (j <= right) {temp[k++] = arr[j++];}// 将temp[] => arr[left, right]for (i = 0; i < temp.length; i++) {arr[left + i] = temp[i];}}public static void main(String[] args) {int[] arr = {1, 432, 1, 3243, 54, 32, -10, 43, 90};mergeSort(arr, 0, arr.length - 1);print(arr);}}

看似很复杂,其实一点也不简单。注意点写在代码里了。只能说用Java写算法,真的头大。

python版归并排序

python版本归并排序

没错,就短短的四行。简洁多了。

接下来,就是重点,如何求1-1个亿数字的和呢?多线程+分段会是不错的选择

  • 1-1_0000
  • 1_0001-2_0000
  • 2_0001-3_0000
  • ……
  • 9999_0000-10000_0000

原理就是这个原理,多线程分段的求和,最后再把总体的和算出来。至少两点是确定的,线程池+Futuretask

多线程求和

public class ThreadPoolDemo {@SneakyThrowspublic static void main(String[] args) {int[] arr = new int[10_0000];for (int i = 0; i < arr.length; i++) {arr[i] = i + 1;}StopWatch stopWatch = new StopWatch();stopWatch.start();ExecutorService executor = Executors.newFixedThreadPool(10);int sum = 0;int chunkSize = arr.length / 10;for (int i = 0; i < 10; i++) {int start = i * chunkSize;int end = (i == 9) ? arr.length : (start + chunkSize);sum += executor.submit(new SumTask(arr, start, end)).get();}executor.shutdown();stopWatch.stop();System.out.println("Sum of 1 to 100000 is: " + sum);System.out.println("代码执行时间:" + stopWatch.getLastTaskTimeMillis() + "毫秒");}
}class SumTask implements Callable<Integer> {private final int[] arr;private final int start;private final int end;public SumTask(int[] arr, int start, int end) {this.arr = arr;this.start = start;this.end = end;}@Overridepublic Integer call() {int sum = 0;for (int i = start; i < end; i++) {sum += arr[i];}return sum;}
}

看着很多,核心的一段就是这个:

for (int i = 0; i < 10; i++) {int start = i * chunkSize;int end = (i == 9) ? arr.length : (start + chunkSize);sum += executor.submit(new SumTask(arr, start, end)).get();
}

创建任务->装进线程池->获得结果->关闭线程池。

但是,在这种情况下,还能继续的优化吗?其实也是可以的,因为现在数组还是太长了,而且计算的线程不是足够的多,性能上肯定不是最优的。

多线程+分治求和

这就是今天的主角:多线程+分治实现求和。还是先看代码:

public class SumRecursive {public static class RecursiveSumTask implements Callable<Long> {// 拆分粒度public static final int THRESHOLD = 10_0000;int low;int high;int[] arr;ExecutorService executorService;RecursiveSumTask(ExecutorService executorService, int[] arr, int low, int high) {this.executorService = executorService;this.arr = arr;this.low = low;this.high = high;}@Overridepublic Long call() throws Exception {long result = 0;if (high - low < THRESHOLD) {for (int i = low; i < high; i++) {result += arr[i];}} else {int mid = (low + high) / 2;RecursiveSumTask leftTask = new RecursiveSumTask(executorService, arr, low, mid);RecursiveSumTask rightTask = new RecursiveSumTask(executorService, arr, mid, high);Future<Long> lr = executorService.submit(leftTask);Future<Long> rr = executorService.submit(rightTask);result = lr.get() + rr.get();}return result;}}@SneakyThrowspublic static void main(String[] args) {int[] arr = new int[10000_0000];for (int i = 0; i < arr.length; i++) {arr[i] = i + 1;}StopWatch stopWatch = new StopWatch();stopWatch.start();ExecutorService executorService = Executors.newCachedThreadPool();RecursiveSumTask recursiveSumTask = new RecursiveSumTask(executorService, arr, 0, arr.length);Long result = executorService.submit(recursiveSumTask).get();executorService.shutdown();stopWatch.stop();System.out.println("Sum of 1 to 100000 is: " + result);System.out.println("代码执行时间:" + stopWatch.getLastTaskTimeMillis() + "毫秒");}}

说实话,代码在显示器上显示真的太好看了,忍不住的截图分享了。

代码截图

那这里的不同点在于使用了分治思想,当我们的数组的长度小于阈值的时候,就直接计算和;但是大于阈值的之后,就会继续的拆分。

总之总体的设计和逻辑真的像极了上文提到的MergeSort,先分的足够小,然后合并,获得最终的结果。

当然,这种设计也并不是最好的,因为我们的线程池设计,或者说线程池等待队列的大小是不好把控的,所以我们线程池的等待队列是2147483647长度的同步队列。完了,又要考虑到OOM!

接下来会分享forkjoin,期待继续关注!文章代码点击这里。

与shigen一起,每天不一样!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/800363.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大模型实践:如何选择适合自己场景的Prompt框架?

1. 选择适合自己场景的Prompt框架需要考虑哪些因素&#xff1f; 以下是一些关键的步骤和考虑点&#xff1a; 理解任务需求&#xff1a;首先&#xff0c;明确你的任务类型&#xff08;如文本生成、问答、文本分类、机器翻译等&#xff09;和具体需求。不同的任务可能需要不同类…

蓝桥杯DFS-最大数字

解题思路 我们从最高位开始要利用自己的1号操作和2号操作保证当前这个数位的数一定要尽可能最大。 然后分别考虑两种操作&#xff0c;首先两种操作不可能混用&#xff0c;因为它们是抵消的效果&#xff0c;所以要么对这个数全使用1操作&#xff0c;要么2操作。假设某个数位的…

[论文精读]Spatio-Temporal Graph Convolution for Resting-State fMRI Analysis

论文网址&#xff1a;Spatio-Temporal Graph Convolution for Resting-State fMRI Analysis | SpringerLink 论文代码&#xff1a;GitHub - sgadgil6/cnslab_fmri: CNS (Computational Neuroscience) Lab project for age/sex classification of fMRI scans 英文是纯手打的&a…

键值数据库Redis——Windows环境下载安装+命令行基本操作+Java操纵Redis

文章目录 前言一、下载与安装&#xff08;Windows环境&#xff09;** 检查数据库连接状态 **** 查看Redis数据库信息 ** 二、Redis五种数据结构与基本操作获取所有的key——keys *清空所有的key——flushall2.1 字符串操作2.2 散列操作2.3 列表操作2.4 集合操作2.5 位图操作 三…

小核引导RTOS---RISC-V C906

文章目录 参考日志编译框架目标fip 启动流程fip文件组成BL2程序 总结思考备注 参考 参考1. How does FSBL load the FreeRTOS on the small core and execute it?参考2. Duo now supports big and little cores?Come and play!Milk-V Duo, start&#xff01;参考3. 使用uboo…

【Mybatis】Mybatis 二级缓存全详解教程

【Mybatis-Plus】Mybatis-Plus 二级缓存全详解 一&#xff0c;Mybatis-Plus介绍 MyBatis-Plus&#xff08;简称MP&#xff09;是一个基于 MyBatis 的增强工具&#xff0c;它简化了 MyBatis 的开发&#xff0c;并且提供了许多便利的功能&#xff0c;帮助开发者更高效地进行持久…

数字电路基础(Digital Circuit Basis )

目录 一、什么是数字电路&#xff1f; &#xff08;Digital Circuit &#xff09; 1.概念 2.分类 3.优点 4.数电与模电的区别 二、数制 (十进制&#xff1a;Decimal) 1.概述 2.进位制 3.基数 4.位权 5.二进制的算术运算 三、编码 (二进制&#xff1a;Binary ) 1.什…

JAVA8新特性

JAVA8新特性 1、函数式编程 主要关注对数据进行了什么操作 1.1 优点 代码简洁 容易理解 易于“并发编程” 2、lamada表达式 (参数列表)->{代码}未使用 new Thread(new Runnable() {Overridepublic void run() {System.out.println(123123123);}}).start(); 使用…

CSS常见样式

字体相关的样式 <style>div{/* 斜体 */font-style: italic;/* 加粗 100-900*/font-weight: 900;/* 字体大小 */font-size: 20px;/* 声明字体格式 */font-family: "微软雅黑";}</style> div内部文字垂直居中 只需要将行高设为其height的大小即可。 div{…

B2985A是德科技B2985A静电计

181/2461/8938产品概述&#xff1a; B2985A 静电计/高阻表具有 0.01 fA&#xff08;0.01 x 10-15 A&#xff09;的分辨率&#xff0c;可帮助您信心十足地测量小电流和最高可达 10 PΩ&#xff08;10 x 1015 Ω&#xff09;的大电阻。 它拥有 4.3 英寸 LCD 彩色液晶屏并配有图形…

WebGL异步绘制多点

异步绘制线段 1.先画一个点 2.一秒钟后&#xff0c;在左下角画一个点 3.两秒钟后&#xff0c;我再画一条线段 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"…

redis的简单操作

redis中string的操作 安装 下载可视化软件&#xff1a;https://gitee.com/qishibo/AnotherRedisDesktopManager/releases。 Mac安装redis&#xff1a; brew install redisWindows安装redis: 安装包下载地址&#xff1a;https://github.com/tporadowski/redis/releases 1.…

C++:类和对象(上)

1.类的引入 C语言结构体中只能定义变量&#xff0c;在C中&#xff0c;结构体内不仅可以定义变量&#xff0c;也可以定义函数&#xff0c;同时C引入class关键字来也能实现这一作用&#xff0c;C更喜欢用class class/struct Stack {int * _array;size_t _capacity;size_t _size…

3.5、文本显示(Text/Span)

创建文本 Text 可通过以下两种方式来创建: string 字符串 效果图 Text(我是一段文本)引用 Resource 资源 资源引用类型可以通过 $r 创建 Resource 类型对象,文件位置为 /resources/base/element/string.json。 引用的资源位于:src/main/resources/base/element/string…

海外仓订单管理存在哪些问题?利用位像素海外仓系统能提升订单管理效率吗?

随着跨境电商业务的蓬勃发展&#xff0c;海外仓的订单量日益攀升&#xff0c;在海外仓的运作中&#xff0c;订单管理是一项看似简单实则复杂繁琐的任务。 然而&#xff0c;大批量订单的涌入&#xff0c;让其管理背后隐藏的问题也随机出现。让我们一起来看看有哪些问题吧&#…

一二三应用开发平台使用手册——系统管理-组织机构-使用说明

概述 平台文档是平台的重要组成部分&#xff0c;这块容易被忽视或不被重视。即使一个平台或系统架构优秀、设计合理、代码优雅&#xff0c;但文档缺失&#xff0c;对于平台的使用方而言&#xff0c;熟悉成本高、难度大。不可避免存在疑问&#xff0c;需要动手尝试验证或翻看源…

(表征学习论文阅读)A Simple Framework for Contrastive Learning of Visual Representations

Chen T, Kornblith S, Norouzi M, et al. A simple framework for contrastive learning of visual representations[C]//International conference on machine learning. PMLR, 2020: 1597-1607. 1. 前言 本文作者为了了解对比学习是如何学习到有效的表征&#xff0c;对本文所…

LeetCode题练习与总结:螺旋矩阵Ⅱ--59

一、题目描述 给你一个正整数 n &#xff0c;生成一个包含 1 到 n^2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[[1,2,3],[8,9,4],[7,6,5]]示例 2&#xff1a; 输入&#xff1…

VMware启动显示“打开虚拟机时出错: 获取该虚拟机的所有权失败”

提示框&#xff08;忘截图了&#xff09;里提示目录C:\Users\mosep\Documents\Virtual Machines\VM-Win10 x64\中的某个文件&#xff08;在我这里好像是VM-Win10 x64.vmx&#xff0c;VM-Win10 x64是我给虚拟机取的名字&#xff09;在被使用中。 找到这个目录&#xff0c;删除.…

【面试题】如何在亿级别用户中检查用户名是否存在?

前言 不知道大家有没有留意过&#xff0c;在使用一些app或者网站注册的时候&#xff0c;提示你用户名已经被占用了&#xff0c;比如我们熟知的《英雄联盟》有些人不知道取啥名字&#xff0c;干脆就叫“不知道取啥名”。 但是有这样困惑的可不止他一个&#xff0c;于是就出现了“…