队列在多线程中的应用

简介:

前言

最近遇到一个问题:有一个几十万行的数据文件,需要提取每一行中的特定字段去请求数据。每一次请求数据可能花费100毫秒的时间,这样的话,如果我们单线程顺序读取文件,发送请求,时间开销很大。如何缩短时间呢?自然想到了多线程处理。可惜自己多线程程序写的并不多,昨晚折腾了许久,终于有所收获!


单线程处理


直接看代码吧:


wKioL1W9flSCpKdqAAFiH8w4feg489.jpg



为了方便,用Thread.sleep的方式进行模拟发送请求获取数据。


运行结果如下:


单线程读取文件并发请求耗时:506047


在单线程处理的情况下,仅仅5000多条数据,就花费了8分多钟!



队列+多线程处理

思路:


用一个线程A去读取文件,将每一行放入到队列Q中;


开启多个线程B去同步的读取队列Q中的数据并发送请求;


线程A和线程B之间通过队列Q进行了交互,队列Q应该是阻塞队列;


线程A的结束,很好说,就是文件读取完毕;那么线程B什么时候结束呢?而且线程B是一组线程,又如何确保他们都正常结束呢?



下面我们先看看线程A的代码吧:


wKioL1W9g42ymrYcAAIsgS8ufGo972.jpg


线程A是一个读取文件形成队列Q的任务,注意下面几点:


  • 构造方法中,队列是外部传入的


  • 定义了一个public属性END,在文件读取最后被放入到了队列中,这是为了通知线程B如果读到了END就可以结束了


  • 放入队列中的方法用的是阻塞式的put



我们在看看线程B的代码:


首先看看属性定义以及构造方法


wKiom1W9g52QJvXEAADdQvnE6TI311.jpg


同样的,队列是由外部传入构造方法;为了方便,给每一个线程B一个标示。


我们重点关注下线程B的run方法:


wKioL1W9hijz2dUoAAHqWTVDo50480.jpg


说明:


  • 首先是一个while循环,如果读取到了队列中的END标示,那么while结束,线程结束


  • 这里取出队首的方法是阻塞式的take


  • 由于队列中的一行,应该只能被一个线程B处理,因此加锁处理取出队首的过程


  • 如果一个线程B读取到了END标示,由于END是读取并删除了,为了其他线程B尽快结束,应该将END继续放入到队列中



主程序部分:


wKioL1W9iBGDfOKoAAILDd0fSJg242.jpg


在主程序部分,我们定义了阻塞队列及其大小,启动一个线程A,以及多个线程B。


运行结果:


线程[13] 处理167

线程[22] 处理167

线程[28] 处理167

线程[1] 处理167

线程[29] 处理167

线程[27] 处理167

线程[25] 处理167

线程[21] 处理167

线程[18] 处理167

线程[20] 处理167

线程[0] 处理168

线程[4] 处理168

线程[19] 处理168

线程[7] 处理168

线程[15] 处理168

线程[23] 处理168

线程[14] 处理168

线程[3] 处理168

线程[17] 处理168

线程[8] 处理168

线程[5] 处理168

线程[2] 处理168

线程[6] 处理168

线程[24] 处理168

线程[12] 处理168

线程[9] 处理168

线程[11] 处理168

线程[16] 处理168

线程[26] 处理168

线程[10] 处理168

队列 + 多线程同步 读取文件并发请求耗时:16921


可以发现,现在5000多行文件的处理,从原来的8分多钟,变成了现在的16S,多线程实在是太恐怖了,哈哈!


本文转自zfz_linux_boy 51CTO博客,原文链接:http://blog.51cto.com/zhangfengzhe/1680939,如需转载请自行联系原作者


相关文章
|
8月前
|
Java
线程池是什么?线程池在实际工作中的应用
总的来说,线程池是一种有效的多线程处理方式,它可以提高系统的性能和稳定性。在实际工作中,我们需要根据任务的特性和系统的硬件能力来合理设置线程池的大小,以达到最佳的效果。
236 18
|
11月前
|
存储 监控 Java
JAVA线程池有哪些队列? 以及它们的适用场景案例
不同的线程池队列有着各自的特点和适用场景,在实际使用线程池时,需要根据具体的业务需求、系统资源状况以及对任务执行顺序、响应时间等方面的要求,合理选择相应的队列来构建线程池,以实现高效的任务处理。
503 12
|
缓存 Java 开发者
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
836 6
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
252 8
|
12月前
|
监控 Java 数据库连接
Java线程管理:守护线程与用户线程的区分与应用
在Java多线程编程中,线程可以分为守护线程(Daemon Thread)和用户线程(User Thread)。这两种线程在行为和用途上有着明显的区别,了解它们的差异对于编写高效、稳定的并发程序至关重要。
252 2
|
数据采集 存储 数据处理
Python中的多线程编程及其在数据处理中的应用
本文深入探讨了Python中多线程编程的概念、原理和实现方法,并详细介绍了其在数据处理领域的应用。通过对比单线程与多线程的性能差异,展示了多线程编程在提升程序运行效率方面的显著优势。文章还提供了实际案例,帮助读者更好地理解和掌握多线程编程技术。
|
存储 监控 安全
深入理解ThreadLocal:线程局部变量的机制与应用
在Java的多线程编程中,`ThreadLocal`变量提供了一种线程安全的解决方案,允许每个线程拥有自己的变量副本,从而避免了线程间的数据竞争。本文将深入探讨`ThreadLocal`的工作原理、使用方法以及在实际开发中的应用场景。
265 2
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
缓存 安全 C++
C++无锁队列:解锁多线程编程新境界
【10月更文挑战第27天】
834 7
|
消息中间件 存储 安全

热门文章

最新文章