当前位置: 首页 > news >正文

多任务并行处理相关面试题

我自己面试时被问过两次多任务并行相关的问题:

假设现在有10个任务,要求同时处理,并且必须所有任务全部完成才返回结果

这个面试题的难点是:

  • 既然要同时处理,那么肯定要用多线程。怎么设计多线程同时处理任务呢?
  • 要求返回结果,那么就不能用简单的Thread+Runnable了,这个是无返回结果的
  • 最难的是,这些任务彼此间还有关系:任务全部结束才算完成

下面3个Demo,CountDownLatch的结果处理交给大家自行完成。

FutureTask

/*** @author mx*/
public class FutureTaskDemo {private static AtomicInteger count = new AtomicInteger(10);public static void main(String[] args) throws ExecutionException, InterruptedException {// 准备10个线程ExecutorService executorService = Executors.newFixedThreadPool(10);// 收集每个任务的结果List<Future<Integer>> resultList = new ArrayList<>();long start = System.currentTimeMillis();// 并行处理10个任务for (int i = 0; i < 10; i++) {// 准备任务Callable<Integer> task = () -> {// 模拟任务耗时 0~4秒int seconds = ThreadLocalRandom.current().nextInt(5);TimeUnit.SECONDS.sleep(seconds);System.out.println("task is completed! cost:" + seconds + "s left: " + count.decrementAndGet());// 模拟返回结果return 1;};// 提交任务Future<Integer> partResult = executorService.submit(task);// 收集结果resultList.add(partResult);}int result = 0;// 阻塞获取并累加结果for (Future<Integer> future : resultList) {result += future.get();}// 最终全部任务完成,总耗时取决于最耗时的任务时长System.out.println("all task is completed! result=" + result + " cost: " + (System.currentTimeMillis() - start) + "ms");}
}

结果展示

task is completed! cost:0s left: 9

task is completed! cost:1s left: 8

task is completed! cost:1s left: 7

task is completed! cost:2s left: 6

task is completed! cost:3s left: 4

task is completed! cost:3s left: 5

task is completed! cost:3s left: 3

task is completed! cost:3s left: 1

task is completed! cost:3s left: 2

task is completed! cost:4s left: 0

all task is completed! result=10 cost: 4110ms

我原先还写过另一个复杂版本:

/*** @author mx*/
public class FutureTaskDemo {private static AtomicInteger count = new AtomicInteger(10);public static void main(String[] args) throws ExecutionException, InterruptedException {// 准备10个线程ExecutorService executorService = Executors.newFixedThreadPool(10);// 收集任务List<Callable<Integer>> taskList = new ArrayList<>();// 收集结果List<Future<Integer>> resultList = new ArrayList<>();long start = System.currentTimeMillis();// 先准备10个任务for (int i = 0; i < 10; i++) {Callable<Integer> task = () -> {// 模拟任务耗时 0~4秒int seconds = ThreadLocalRandom.current().nextInt(5);TimeUnit.SECONDS.sleep(seconds);System.out.println("task is completed! cost:" + seconds + "s left: " + count.decrementAndGet());// 模拟返回结果return 1;};// 收集任务taskList.add(task);}// 10个任务并行执行for (int i = 0; i < 10; i++) {// 从任务列表取出任务,丢到线程池执行Future<Integer> partResult = executorService.submit(taskList.get(i));// 收集异步结果resultList.add(partResult);}// 最终结果,用于累加int result = 0;// 是否全部结束,否则一直循环等待while (notFinished(resultList)) {// wait for all task to be completed...}// 主线程执行到这,肯定全部任务已经结束,所以get()会立即返回结果,不会再阻塞等待for (Future<Integer> future : resultList) {result += future.get();}// 最终全部任务完成,总耗时取决于最耗时的任务时长System.out.println("all task is completed! result=" + result + " cost: " + (System.currentTimeMillis() - start) + "ms");}/*** 是否全部完成** @param list* @return*/private static boolean notFinished(List<Future<Integer>> list) {for (Future<Integer> future : list) {if (!future.isDone()) {return true;}}return false;}
}

结果展示

task is completed! cost:0s left: 9

task is completed! cost:0s left: 8

task is completed! cost:2s left: 7

task is completed! cost:3s left: 6

task is completed! cost:3s left: 3

task is completed! cost:3s left: 4

task is completed! cost:3s left: 5

task is completed! cost:4s left: 2

task is completed! cost:4s left: 1

task is completed! cost:4s left: 0

all task is completed! result=10 cost: 4051ms

在当前场景下,其实没必要。

有些人可能觉得第一个版本会出现以下问题:

假设总共就2个任务,但是第一个任务耗时3秒,第二个任务耗时1秒。第二个任务的1秒是建立在第一个任务的3秒后,所以总耗时就变成了4秒。

实际上并不会。当future1#get()阻塞获取第一个任务结果的过程中,第二个任务已经完成,所以future2.get()不会再阻塞,而是直接返回结果。

CountDownLatch

CountDownLatch是什么?学名叫闭锁,俗名叫门栓。

/*** @author mx*/
public class CountDownLatchDemo {public static void main(String[] args) throws InterruptedException {// 1.先看简单demo,了解下CountDownLatchmainThreadAndAsyncThread();// 2.尝试使用CountDownLatch解决任务并行问题(不处理结果)
//        multiThreadTask();}/*** CountDownLatch简单demo** @throws InterruptedException*/private static void mainThreadAndAsyncThread() throws InterruptedException {// 准备一个countDownLatch,设置10,相当于给门加了10把锁CountDownLatch countDownLatch = new CountDownLatch(10);long start = System.currentTimeMillis();// 副线程去处理任务,每个任务耗时1秒,每处理完1个任务就解开一把锁new Thread(() -> {for (int i = 0; i < 10; i++) {try {Thread.sleep(1000L);} catch (InterruptedException e) {e.printStackTrace();}countDownAndPrint(countDownLatch, 1);}}).start();// 一夫当关,万夫莫开。只要门上10把锁没有全部解开,任何线程都别想想往下走countDownLatch.await();System.out.println("all task is completed! cost: " + (System.currentTimeMillis() - start) + "ms");}/*** CountDownLatch应用:演示10个任务并行执行,全部完成后返回结果** @throws InterruptedException*/private static void multiThreadTask() throws InterruptedException {// 准备一个countDownLatch,设置10,相当于给门加了10把锁CountDownLatch countDownLatch = new CountDownLatch(10);long start = System.currentTimeMillis();// 启动10个线程执行任务for (int i = 0; i < 10; i++) {new Thread(() -> {try {// 线程进来执行任务,随机睡0~4秒int seconds = ThreadLocalRandom.current().nextInt(5);TimeUnit.SECONDS.sleep(seconds);// 每完成一个任务,解开一把锁countDownAndPrint(countDownLatch, seconds);} catch (InterruptedException e) {e.printStackTrace();}}).start();}// 一夫当关,万夫莫开。只要门上10把锁没有全部解开,任何线程都别想想往下走countDownLatch.await();System.out.println("all task is completed! cost: " + (System.currentTimeMillis() - start) + "ms");}/*** countDown()并且打印,其实是不需要加synchronized的,这里只是为了多线程环境下正确打印** @param countDownLatch* @param seconds*/private static synchronized void countDownAndPrint(CountDownLatch countDownLatch, int seconds) {countDownLatch.countDown();System.out.println("task completed, cost: " + seconds + "s left: " + countDownLatch.getCount());}
}

结果展示

task is completed! cost:0s left: 9

task is completed! cost:0s left: 8

task is completed! cost:0s left: 7

task is completed! cost:2s left: 6

task is completed! cost:2s left: 5

task is completed! cost:2s left: 3

task is completed! cost:2s left: 4

task is completed! cost:3s left: 2

task is completed! cost:4s left: 1

task is completed! cost:4s left: 0

all task is completed! result=10 cost: 4049ms

CompletableFuture

顺便说一句,上面的两个Demo都是闹着玩呢,实际开发别傻不拉几地自己写哈...会被打,而且是背身单打颜扣的那种。

/*** @author mx*/
public class CompletableFutureDemo {private static AtomicInteger count = new AtomicInteger(10);public static void main(String[] args) throws InterruptedException, ExecutionException {// 准备10个线程ExecutorService executorService = Executors.newFixedThreadPool(10);// 收集结果List<CompletableFuture<Integer>> resultList = new ArrayList<>();long start = System.currentTimeMillis();// 任务并行for (int i = 0; i < 10; i++) {CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {// 模拟任务耗时 0~4秒try {int seconds = ThreadLocalRandom.current().nextInt(5);TimeUnit.SECONDS.sleep(seconds);System.out.println("task is completed! cost:" + seconds + "s left: " + count.decrementAndGet());} catch (InterruptedException e) {e.printStackTrace();}// 模拟返回结果return 1;}, executorService);resultList.add(completableFuture);}// 处理结果int result = 0;for (CompletableFuture<Integer> completableFuture : resultList) {result += completableFuture.get();}// 最终全部任务完成,总耗时取决于最耗时的任务时长System.out.println("all task is completed! result=" + result + " cost: " + (System.currentTimeMillis() - start) + "ms");}
}

结果展示

task is completed! cost:0s left: 9

task is completed! cost:0s left: 8

task is completed! cost:0s left: 7

task is completed! cost:0s left: 6

task is completed! cost:2s left: 5

task is completed! cost:3s left: 4

task is completed! cost:3s left: 3

task is completed! cost:3s left: 2

task is completed! cost:4s left: 1

task is completed! cost:4s left: 0

all task is completed! result=10 cost: 4051ms

实际开发案例

public class CompletableFutureDemo {private static AtomicInteger count = new AtomicInteger(2);public static void main(String[] args) throws InterruptedException, ExecutionException {// 准备10个线程ExecutorService executorService = Executors.newFixedThreadPool(2);long start = System.currentTimeMillis();// 模拟处理订单CompletableFuture<Void> dealOrder = CompletableFuture.runAsync(() -> {// 模拟任务耗时 0~4秒try {int seconds = ThreadLocalRandom.current().nextInt(5);TimeUnit.SECONDS.sleep(seconds);System.out.println("task is completed! cost:" + seconds + "s left: " + count.decrementAndGet());} catch (InterruptedException e) {e.printStackTrace();}}, executorService);// 模拟处理库存CompletableFuture<Void> dealStock = CompletableFuture.runAsync(() -> {// 模拟任务耗时 0~4秒try {int seconds = ThreadLocalRandom.current().nextInt(5);TimeUnit.SECONDS.sleep(seconds);System.out.println("task is completed! cost:" + seconds + "s left: " + count.decrementAndGet());} catch (InterruptedException e) {e.printStackTrace();}}, executorService);// 可变参数,可以传任意个CompletableFuture,阻塞等待所有任务完成CompletableFuture.allOf(dealOrder, dealStock).get();// 最终全部任务完成,总耗时取决于最耗时的任务时长System.out.println("all task is completed! cost: " + (System.currentTimeMillis() - start) + "ms");}
}

结果展示

task is completed! cost:2s left: 1

task is completed! cost:3s left: 0

all task is completed! cost: 3058ms

相关文章:

多任务并行处理相关面试题

我自己面试时被问过两次多任务并行相关的问题&#xff1a; 假设现在有10个任务&#xff0c;要求同时处理&#xff0c;并且必须所有任务全部完成才返回结果 这个面试题的难点是&#xff1a; 既然要同时处理&#xff0c;那么肯定要用多线程。怎么设计多线程同时处理任务呢&…...

Shell脚本学习笔记

1. 写在前面 工作中&#xff0c;需要用到写一些shell脚本去完成一些简单的重复性工作&#xff0c; 于是就想系统的学习下shell脚本的相关知识&#xff0c; 本篇文章是学习shell脚本整理的学习笔记&#xff0c;内容参考主要来自C语言中文网&#xff0c; 学习过程中&#xff0c;…...

ROS-安装xacro

安装 运行下列命令进行安装&#xff0c;xxxxxx处更改为自己的版本 sudo apt-get install ros-xxxxxx-xacro运行 输入下列命令 roscd xacro如果没有报错&#xff0c;并且进入了xacro软件包的目录&#xff0c;则表示安装成功。 参考&#xff1a; [1]https://wenku.csdn.net/ans…...

为什么说 $mash 是 Solana 上最正统的铭文通证?

早在 2023 年的 11 月&#xff0c;包括 Solana、Avalanche、Polygon、Arbitrum、zkSync 等生态正在承接比特币铭文生态外溢的价值。当然&#xff0c;因铭文赛道过于火爆&#xff0c;当 Avalanche、BNB Chain 以及 Polygon 等链上 Gas 飙升至极值&#xff0c;Arbitrum、zkSync 等…...

安装elasticsearch、kibana、IK分词器、扩展IK词典

安装elasticsearch、kibana、IK分词器、扩展IK词典 后面还会安装kibana&#xff0c;这个会提供可视化界面方面学习。 需要注意的是elasticsearch和kibana版本一定要一样&#xff01;&#xff01;&#xff01; 否则就像这样 elasticsearch 1、创建网络 因为我们还需要部署k…...

Spring中常见的BeanFactory后处理器

常见的BeanFacatory后处理器 先给出没有添加任何BeanFactory后处理器的测试代码 public class TestBeanFactoryPostProcessor {public static void main(String[] args) {GenericApplicationContext context new GenericApplicationContext();context.registerBean("co…...

FPGA LCD1602驱动代码 (已验证)

一.需求解读 1.需求 在液晶屏第一行显示“HELLO FPGA 1234!” 2. 知识背景 1602 液晶也叫 1602 字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵 型液晶模块。它由若干个 5X7 或者 5X11 等点阵字符位组成,每个点阵字符位都可以显示一 个字符,每位之间有一个点距的…...

c++编程要养成的好习惯

1、缩进 你说有缩进看的清楚还是没缩进看的清楚 2、i和i i运行起来和i更快 3、 n%20和n&1 不要再用n%20来判断n是不是偶数了&#xff0c;又慢又土&#xff0c;用n&10&#xff0c;如果n&10就说明n是偶数 同理&#xff0c;n&11说明n是奇数 4、*2和<<…...

后台管理项目的多数据源方案

引言 在互联网开发公司中&#xff0c;往往伴随着业务的快速迭代&#xff0c;程序员可能没有过多的时间去思考技术扩展的相关问题&#xff0c;长久下来导致技术过于单一。为此最近在学习互联网思维&#xff0c;从相对简单的功能开始做总结&#xff0c;比如非常常见的基础数据的…...

视频美颜SDK趋势畅想:未来发展方向与应用场景

当下&#xff0c;视频美颜SDK正不断演进&#xff0c;本文将深入探讨视频美颜SDK的发展趋势&#xff0c;探讨未来可能的方向和广泛的应用场景。 1.深度学习与视频美颜的融合 未来&#xff0c;我们可以期待看到更多基于深度学习算法的视频美颜SDK&#xff0c;为用户提供更高质量…...

C++ const 限定符的全面介绍

C const 限定符的全面介绍 1. const 修饰基本数据类型 定义 const 修饰的基本数据类型变量&#xff0c;值不可改变。 语法 const type variable value;特点 不可变性&#xff0c;增加代码可读性。 作用 定义不可修改的常量。 使用场景 全局常量、配置项。 注意事项…...

Vue 中的 ref 与 reactive:让你的应用更具响应性(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…...

华为云CCE-集群内访问-根据ip访问同个pod

华为云CCE-集群内访问-根据ip访问同个pod 问题描述&#xff1a;架构如下&#xff1a;解决方法&#xff1a; 问题描述&#xff1a; 使用service集群内访问时&#xff0c;由于启用了两个pod&#xff0c;导致请求轮询在两个pod之间&#xff0c;无法返回正确的结果。 架构如下&am…...

Kasada p.js (x-kpsdk-cd、x-kpsdk-ct、integrity)

提供x-kpsdk-cd的API服务 详细请私信~ 可试用~ V:zhzhsgg 一、简述 integrity是通过身份验证Kasada检测机器人流量后获得的一个检测结果&#xff08;数据完整性&#xff09; x-kpsdk-cd 是经过编码计算等等获得。当你得到正确的解决验证码值之后&#xff0c;解码会看到如下图…...

Thinkphp 5框架学习

TP框架主要是通过URL实现操作 http://servername/index.php/模块/控制器/操作/参数/值.. index.php 为入口文件&#xff0c;在 public 目录内的 index.php 文件; 模块在 application 目录下默认有一个 index 目录&#xff0c;这就是一个模块; 而在 index 目录下有一个 contro…...

麒麟云增加计算节点

一、安装基座系统并配置好各项设置 追加的计算节点服务器&#xff0c;安装好系统&#xff0c;把主机名、网络网线&#xff08;网线要和其他网线插的位置一样&#xff09;、hosts这些配置好&#xff0c;在所有节点的/etc/hosts里面添加信息 在控制节点添加/kylincloud/multinod…...

使用Redis进行搜索

文章目录 构建反向索引 构建反向索引 在Begin-End区域编写 tokenize(content) 函数&#xff0c;实现文本标记化的功能&#xff0c;具体参数与要求如下&#xff1a; 方法参数 content 为待标记化的文本&#xff1b; 文本标记的实现&#xff1a;使用正则表达式提取全小写化后的…...

Oracle修改用户密码

文章目录 Oracle修改用户密码Oracle用户锁定常见的两种状态Oracle用户锁定和解锁 Oracle修改用户密码 使用sys或system使用sysdba权限登录&#xff0c;然后执行以下命令修改密码&#xff1a; alter user 用户名 identified by 密码;密码过期导致的锁定&#xff0c;也通过修改…...

​LeetCode解法汇总1276. 不浪费原料的汉堡制作方案

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 描述&#xff1a; 圣诞活动预…...

Vue解决跨域问错误:has been blocked by CORS policy 后端跨域配置

解决跨域问题后端跨域配置代码&#xff1a; /*** 作者 hua* 描述 跨域配置*/ Configuration public class WebConfiguration implements WebMvcConfigurer {/*** 跨域配置对象* return CorsConfiguration对象*/private CorsConfiguration corsConfig() {CorsConfiguration cor…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...