陌陌笔试--并发打印文件内最有钱的老板的消费金额(算法)

题目:

算法中需要打印消费前十老板的消费金额,解决保留两位小数,并发是 JAVA 中的常考题,
在这里插入图片描述

我这里简单模拟下了数据,关键数据是用户id和消费金额。

解题思路:

1. 最简单的思路是单线程,偷懒(dog),

public class Main {public static void main(String[] args) throws FileNotFoundException {Scanner scanner = new Scanner(new File("C:\\Users\\15031\\Desktop\\momo\\momo\\src\\data.txt"));System.out.println(scanner.nextLine());HashMap<Integer,Double>map = new HashMap<>();String s = scanner.nextLine();while (scanner.hasNextLine()) {String line = scanner.nextLine();String[] partLine = line.split(" ");int userId = Integer.parseInt(partLine[1]);double order = Double.parseDouble(partLine[2]);map.put(userId,map.getOrDefault(userId,0d) + order);}Queue<Map.Entry<Integer,Double>>queue = new PriorityQueue<>((entry0,entry1)->Double.compare(entry0.getValue(),entry1.getValue()));for(Map.Entry<Integer,Double> e : map.entrySet()){if(queue.size() < 10){queue.offer(e);}else {queue.poll();queue.offer(e);}}for(Map.Entry<Integer,Double> e : queue){System.out.println(e.getKey()+","+String.format("%.2f", e.getValue()));}}
}

在这里插入图片描述

我们可以使用文件流读取数据偷懒,然后再使用hashmap统计出现的次数,然后再使用优先队列统计前k个字符串,然后输出。

2. 多线程解决思路

多线程实际上要复杂的多,要考虑一个线程处理多少数据合适,当然,这是最笨的方法,甚至还要考虑是否要读入到内存里,如果数据较多,可能考虑内存占用问题。简单数据还好,可能几十万行也就占用几百兆内存。

在这里插入图片描述

  1. 内存缓冲器区

我们使用BlockingQueue,该队列是生产者消费者模型中常用的类

        BlockingQueue<String> queue = new LinkedBlockingQueue<>();
  1. 这里我们使用一个线程做生产者,多线程不知道怎么生产(dog),BlockingQueue做缓冲区。

生产者,生产者文件流如果使用多线程读取会比较复杂,故我们使用单线程,还有一个问题是读一行感觉消费处理起来也并不太高。(当然这里就先偷懒了)

producerExecutor.submit(() -> {try (Scanner scanner = new Scanner(new File("C:\\Users\\15031\\Desktop\\momo\\momo\\src\\data.txt"))) {while (scanner.hasNextLine()) {queue.put(scanner.nextLine());}for (int j = 0; j < CONSUMER_COUNT; j++) {queue.put("EOF"); // End-of-file markers for consumer threads}} catch (FileNotFoundException | InterruptedException e) {e.printStackTrace();}});
  1. 消费者处理

消费者这里我们直接使用线程池处理了,需要注意的是线程数并非越多越好,最好和计算机 cpu 核心数有相关性,同时这里一行数据切换一个线程也并不能提升效率(dog)

for (int i = 0; i < CONSUMER_COUNT; i++) {consumerExecutor.submit(() -> {try {while (true) {List<String> batch = queue.take();if (batch.contains("EOF")) {queue.put(Collections.singletonList("EOF")); // Pass the marker to other consumersbreak;}for (String line : batch) {String[] partLine = line.split(" ");int userId = Integer.parseInt(partLine[1]);double order = Double.parseDouble(partLine[2]);map.merge(userId, order, Double::sum);}}} catch (InterruptedException e) {e.printStackTrace();}});}

为什么要添加消费者数量的EOF 而不是先peek判断,然后再取出呢?

  • 线程安全:在使用 peek() 和 poll() 时,需要确保操作的原子性。使用两步操作会强行把原子操作变成不原子的,在操作之间peek()的数据可能被修改,造成线程安全问题。
  • 简化实现:尽可能简化并发模型可以减少复杂性和错误的可能性。直接使用 take() 可以确保每个元素只被处理一次,逻辑更为简单。
  1. 总体代码
```java
public class Main {private static final int PRODUCER_COUNT = 1; // 生产者threadsprivate static final int CONSUMER_COUNT = 4; // 消费者threadsprivate static final int TOP_N = 10; // Top N users by order amountpublic static void main(String[] args) throws FileNotFoundException {BlockingQueue<String> queue = new LinkedBlockingQueue<>();ConcurrentHashMap<Integer, Double> map = new ConcurrentHashMap<>();ExecutorService producerExecutor = Executors.newFixedThreadPool(PRODUCER_COUNT);ExecutorService consumerExecutor = Executors.newFixedThreadPool(CONSUMER_COUNT);// Producer threadsfor (int i = 0; i < PRODUCER_COUNT; i++) {producerExecutor.submit(() -> {try (Scanner scanner = new Scanner(new File("C:\\Users\\15031\\Desktop\\momo\\momo\\src\\data.txt"))) {while (scanner.hasNextLine()) {queue.put(scanner.nextLine());}for (int j = 0; j < CONSUMER_COUNT; j++) {queue.put("EOF"); // End-of-file markers for consumer threads}} catch (FileNotFoundException | InterruptedException e) {e.printStackTrace();}});}// Consumer threadsfor (int i = 0; i < CONSUMER_COUNT; i++) {consumerExecutor.submit(() -> {try {while (true) {String line = queue.take();if ("EOF".equals(line)) {queue.put("EOF"); // Pass the marker to other consumersbreak;}String[] partLine = line.split(" ");int userId = Integer.parseInt(partLine[1]);double order = Double.parseDouble(partLine[2]);map.merge(userId, order, Double::sum);}} catch (InterruptedException e) {e.printStackTrace();}});}producerExecutor.shutdown();consumerExecutor.shutdown();try {producerExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);consumerExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);} catch (InterruptedException e) {e.printStackTrace();}// Process the map to find top N usersPriorityQueue<Map.Entry<Integer, Double>> queueTopN = new PriorityQueue<>(Map.Entry.comparingByValue());for (Map.Entry<Integer, Double> entry : map.entrySet()) {if (queueTopN.size() < TOP_N) {queueTopN.offer(entry);} else if (entry.getValue() > queueTopN.peek().getValue()) {queueTopN.poll();queueTopN.offer(entry);}}List<Map.Entry<Integer, Double>> topNList = new ArrayList<>(queueTopN);topNList.sort((e0,e1)-> (int) (e0.getValue()-e1.getValue()));for (Map.Entry<Integer, Double> entry : topNList) {System.out.println(entry.getKey() + "," + String.format("%.2f", entry.getValue()));}}
}

思考:

😄 这里主要是对生产者和消费者模式的一个总结和复习,这些处理模式可能平时没感觉怎么用,但是一结合实际,我们就立马可以感受到这些处理的模式的优异之处了。

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

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

相关文章

【面试系列】Go 语言高频面试题

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题. ⭐️ AIGC时代的创新与未来&#xff1a;详细讲解AIGC的概念、核心技术、…

狂神说Java之 rabbitmq高级分布式事务

分布式事务的完整架构图 案例场景分析 案例一&#xff1a;用RestTemplate演示&#xff08;不可靠生产&#xff0c;会出现问题&#xff09; 创建一个订单模块 创建一个OrderDataBaseService服务 创建一个order的service服务&#xff0c;调用saveOrder()方法 创建一个运单模块…

2024.06.20校招 实习 内推 面经

绿*泡*泡VX&#xff1a; neituijunsir 交流*裙 &#xff0c;内推/实习/校招汇总表格 1、校招 | 速腾聚创 RoboSense“天才罗伯特”计划面向全球招募 &#xff08;内推&#xff09; 校招 | 速腾聚创 RoboSense“天才罗伯特”计划面向全球招募 &#xff08;内推&#xff09; …

java.util.function实现原理和Java使用场景【Function、Predicate集合转换过滤,BiConsumer事件处理】

简介 java.util.function 是 Java 8 引入的一个功能包,它包含了多种函数式接口的定义,使得在 Java 中进行函数式编程变得更为方便。下面我将分别介绍 java.util.function 的作用、实现原理、常用 Java 使用场景以及代码示例。 作用 java.util.function 的主要作用是为 Jav…

Java导出Excel并邮件发送

一、导出Excel 添加maven依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.10-FINAL</version></dependency><dependency><groupId>org.apache.poi</groupI…

软件设计流程和开发流程及规范(Word)

2 过程总体描述 2.1 过程概述 2.2 过程流程图 3 过程元素描述 3.1 产品方案 3.2 产品设计 3.3 产品实现 获取方式&#xff1a;本文末个人名片直接获取。 软件资料清单列表部分文档清单&#xff1a;工作安排任务书&#xff0c;可行性分析报告&#xff0c;立项申请审批表&#x…

找不到vcomp140.dll怎么办,总结多种解决方法

​在日常使用电脑的过程中&#xff0c;我们可能会遇到一些错误提示&#xff0c;其中之一就是“vcomp140.dll丢失”。那么&#xff0c;vcomp140.dll是什么&#xff1f;它为什么会丢失&#xff1f;丢失后对电脑有什么影响&#xff1f;又该如何解决呢&#xff1f;本文将详细介绍vc…

根据肥胖类型选择减调方向收获窈窕身材

我们生活中胖子很多&#xff0c;从胖到瘦的人也不少&#xff0c;但瘦了后对自己身材满意的人却是不多的&#xff0c;很多人瘦了也只是减掉了身上的赘肉而已&#xff0c;大体的身形却是没有变化的&#xff0c;因此&#xff0c;并不感到满意。因为他们本身的形体是固定的&#xf…

半正定矩阵

在矩阵分析和线性代数中&#xff0c;半正定矩阵&#xff08;Positive Semi-Definite Matrix&#xff0c;简称PSD矩阵&#xff09;是一类重要的矩阵。一个矩阵被称为半正定矩阵有以下几种等价的定义和性质&#xff1a; 定义 一个对称矩阵 M \mathbf{M} M被称为半正定矩阵&…

009、MongoDB的分片策略

目录 MongoDB的分片策略:范围分片vs哈希分片 1. 范围分片(Range Sharding) 1.1 工作原理 1.2 优点 1.3 缺点 1.4 研究支持 2. 哈希分片(Hash Sharding) 2.1 工作原理 2.2 优点 2.3 缺点 2.4 研究支持 3. 选择合适的分片策略 4. 实践案例 4.1 电子商务平台 4.2 社…

SpringBoot-SpringBoot整合Swagger使用教程(图文介绍,一篇就够了)

前言 日常开发中&#xff0c;接口都是和开发文档相结合的。不论是和前端对接还是三方对接亦或者是接口留档&#xff0c;当我们开发完接口后&#xff0c;都需要去创建对应的接口文档。而修改接口后也要修改相对应的接口文档&#xff0c;但是这个真的很容易疏漏。而且相对于繁重的…

WEB攻防【6】——Python考点/CTF与CMS/SSTI模板注入/PYC反编译

#知识点 1、PYC文件反编译 2、python-web-SSTI 3、SSTI模板注入利用分析 SSTI 就是服务器端模板注入 &#xff08;Server-Side Template Injection&#xff09; 当前使用的一些框架&#xff0c;比如python的flask&#xff0c;php的tp&#xff0c;java的spring等一般都采用成…

jQuery的extend方法仅仅是字面意思上的扩展吗?

jQuery中extend的使用方式大多是这样的&#xff1a; jQuery.extend({// Unique for each copy of jQuery on the pageexpando: "jQuery" (version Math.random()).replace(/\D/g, ""),// Assume jQuery is ready without the ready moduleisReady: true,…

存储管理(三):分区表

什么是分区表 假设存在表t&#xff1a; CREATETABLE t (ftimedatetime NOT NULL,c int(11) DEFAULT NULL,KEY (ftime) )ENGINEInnoDB DEFAULT CHARSETlatin1 PARTITION BY RANGE (YEAR(ftime)) (PARTITION p_2017 VALUES LESS THAN (2017) ENGINE InnoDB,PARTITION p_2018 VA…

golang 获取系统的主机 CPU 内存 磁盘等信息

golang 获取系统的主机 CPU 内存 磁盘等信息 要求 需要go1.18或更高版本 官方地址&#xff1a;https://github.com/shirou/gopsutil 使用 #下载包 go get github.com/shirou/gopsutil/v3/cpu go get github.com/shirou/gopsutil/v3/disk go get github.com/shirou/gopsuti…

tr、cut、split、grep -E

目录 tr命令&#xff1a;替换和删除 cut命令&#xff1a;快速裁剪 split命令&#xff1a;文件拆分 文件合并 面试题 1.现在有一个日志文件&#xff0c;有5个G&#xff0c;能不能快速的打开 2.cat合并和paste合并之间的区别&#xff1f; 3.统计当前主机的连接状态&#…

Hadoop3:MapReduce中的Reduce Join和Map Join

一、概念说明 学过MySQL的都知道&#xff0c;join和left join 这里的join含义和MySQL的join含义一样 就是对两张表的数据&#xff0c;进行关联查询 Hadoop的MapReduce阶段&#xff0c;分为2个阶段 一个Map&#xff0c;一个Reduce 那么&#xff0c;join逻辑&#xff0c;就可以…

前端开发的工厂设计模式

在前端开发中&#xff0c;工厂设计模式&#xff08;Factory Pattern&#xff09;是一种非常有用的设计模式&#xff0c;能够帮助我们在创建对象时减少代码的重复性和复杂性。 一、工厂设计模式概述 工厂设计模式是一种创建型设计模式&#xff0c;主要目的是定义一个用于创建对…

2024年建筑八大员(资料员)考试题库,省心高效,轻松通过!

1.插入的图片无法显示&#xff0c;或者显示失真&#xff0c;正确做法是&#xff08;&#xff09;。 A.插人图片是应选中【自动调整图片大小】 B.在下拉【菜单】中选中【按单元格式大小】插入 C.在【格式】下拉中【图片】处打钩 D.在【属性】下拉中选中【工具显示】 答案&a…

机械培训元宇宙:开启未来教育与职业培训的新篇章

随着科技的飞速发展&#xff0c;特别是虚拟现实&#xff08;VR&#xff09;、增强现实&#xff08;AR&#xff09;和人工智能&#xff08;AI&#xff09;等先进技术的广泛应用&#xff0c;我们正逐渐步入一个全新的时代——元宇宙。在这个虚拟的、由无数个并行宇宙组成的世界中…